@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,54 @@
|
|
|
1
|
+
const KEY_ALIASES: Record<string, string> = {
|
|
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
|
+
|
|
35
|
+
export function mapGeminiKey(key: string): string {
|
|
36
|
+
const trimmed = key.trim();
|
|
37
|
+
if (!trimmed) {
|
|
38
|
+
throw new Error("Key must be a non-empty string");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (trimmed.length === 1) {
|
|
42
|
+
return trimmed;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return KEY_ALIASES[trimmed.toLowerCase()] ?? trimmed;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function mapGeminiKeys(keys: string[]): string[] {
|
|
49
|
+
return keys.map(mapGeminiKey);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function selectAllShortcut(platform = process.platform): string {
|
|
53
|
+
return platform === "darwin" ? "Meta+A" : "Control+A";
|
|
54
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
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, type TokenUsage } from "../shared/cost.js";
|
|
5
|
+
import { readWebpAsBase64 } from "./screenshot.js";
|
|
6
|
+
import {
|
|
7
|
+
AgentRunError,
|
|
8
|
+
type ComputerUsePage,
|
|
9
|
+
type IntentListener,
|
|
10
|
+
type InteractionClient,
|
|
11
|
+
type InteractionStep,
|
|
12
|
+
type SafetyConfirmer,
|
|
13
|
+
type ScreenshotSaver,
|
|
14
|
+
type Sleeper,
|
|
15
|
+
} from "./types.js";
|
|
16
|
+
|
|
17
|
+
export interface AgentLoopDeps {
|
|
18
|
+
client: InteractionClient;
|
|
19
|
+
page: ComputerUsePage;
|
|
20
|
+
saveScreenshot: ScreenshotSaver;
|
|
21
|
+
confirmSafety: SafetyConfirmer;
|
|
22
|
+
screenWidth: number;
|
|
23
|
+
screenHeight: number;
|
|
24
|
+
maxTurns: number;
|
|
25
|
+
sleep?: Sleeper;
|
|
26
|
+
readScreenshot?: (filePath: string) => Promise<string>;
|
|
27
|
+
onIntent?: IntentListener;
|
|
28
|
+
signal?: AbortSignal;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface AgentLoopResult {
|
|
32
|
+
status: "completed" | "max_turns" | "safety_denied";
|
|
33
|
+
turns: number;
|
|
34
|
+
finalText: string;
|
|
35
|
+
usage: TokenUsage;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async function screenshotBase64(
|
|
39
|
+
saveScreenshot: ScreenshotSaver,
|
|
40
|
+
actionName: string,
|
|
41
|
+
readScreenshot: (filePath: string) => Promise<string>,
|
|
42
|
+
): Promise<string> {
|
|
43
|
+
const filePath = await saveScreenshot(actionName);
|
|
44
|
+
return readScreenshot(filePath);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async function throwIfAborted(signal: AbortSignal | undefined, usage: TokenUsage): Promise<void> {
|
|
48
|
+
if (signal?.aborted) {
|
|
49
|
+
throw new AgentRunError("Agent stopped", usage);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export async function runComputerUseLoop(
|
|
54
|
+
deps: AgentLoopDeps,
|
|
55
|
+
task: string,
|
|
56
|
+
): Promise<AgentLoopResult> {
|
|
57
|
+
const readScreenshot = deps.readScreenshot ?? readWebpAsBase64;
|
|
58
|
+
await throwIfAborted(deps.signal, EMPTY_USAGE);
|
|
59
|
+
const initialImage = await screenshotBase64(deps.saveScreenshot, "start", readScreenshot);
|
|
60
|
+
|
|
61
|
+
const history: InteractionStep[] = [
|
|
62
|
+
{
|
|
63
|
+
type: "user_input",
|
|
64
|
+
content: [
|
|
65
|
+
{ type: "text", text: task },
|
|
66
|
+
{ type: "image", data: initialImage, mime_type: "image/webp" },
|
|
67
|
+
],
|
|
68
|
+
},
|
|
69
|
+
];
|
|
70
|
+
|
|
71
|
+
let finalText = "";
|
|
72
|
+
let usage = EMPTY_USAGE;
|
|
73
|
+
|
|
74
|
+
for (let turn = 1; turn <= deps.maxTurns; turn += 1) {
|
|
75
|
+
await throwIfAborted(deps.signal, usage);
|
|
76
|
+
logger.info(`Computer-use turn ${turn}/${deps.maxTurns}`);
|
|
77
|
+
|
|
78
|
+
let interaction;
|
|
79
|
+
try {
|
|
80
|
+
interaction = await deps.client.create([...history]);
|
|
81
|
+
usage = addUsage(usage, interaction.usage ?? EMPTY_USAGE);
|
|
82
|
+
} catch (error: unknown) {
|
|
83
|
+
if (deps.signal?.aborted) {
|
|
84
|
+
throw new AgentRunError("Agent stopped", usage);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
logger.error("Gemini API call failed", error);
|
|
88
|
+
if (error instanceof AgentRunError) {
|
|
89
|
+
throw new AgentRunError(error.message, addUsage(usage, error.usage));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
throw new AgentRunError(error instanceof Error ? error.message : String(error), usage);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
await throwIfAborted(deps.signal, usage);
|
|
96
|
+
history.push(...interaction.steps);
|
|
97
|
+
const calls = getFunctionCalls(interaction.steps);
|
|
98
|
+
|
|
99
|
+
if (calls.length === 0) {
|
|
100
|
+
finalText = extractModelText(interaction.steps);
|
|
101
|
+
logger.info(`Agent finished: ${finalText || "(no text)"}`);
|
|
102
|
+
return { status: "completed", turns: turn, finalText, usage };
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
let results;
|
|
106
|
+
let terminated;
|
|
107
|
+
let lastScreenshotPath;
|
|
108
|
+
try {
|
|
109
|
+
({ results, terminated, lastScreenshotPath } = await executeFunctionCalls(calls, {
|
|
110
|
+
page: deps.page,
|
|
111
|
+
screenWidth: deps.screenWidth,
|
|
112
|
+
screenHeight: deps.screenHeight,
|
|
113
|
+
saveScreenshot: deps.saveScreenshot,
|
|
114
|
+
confirmSafety: deps.confirmSafety,
|
|
115
|
+
sleep: deps.sleep,
|
|
116
|
+
onIntent: deps.onIntent,
|
|
117
|
+
signal: deps.signal,
|
|
118
|
+
}));
|
|
119
|
+
} catch (error: unknown) {
|
|
120
|
+
if (error instanceof AgentRunError && error.message === "Agent stopped") {
|
|
121
|
+
throw new AgentRunError("Agent stopped", usage);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
throw error;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (terminated) {
|
|
128
|
+
logger.info("Agent stopped after safety denial");
|
|
129
|
+
return { status: "safety_denied", turns: turn, finalText, usage };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const screenshotPath = lastScreenshotPath ?? (await deps.saveScreenshot("state"));
|
|
133
|
+
const image = await readScreenshot(screenshotPath);
|
|
134
|
+
history.push(...buildFunctionResults(results, deps.page.url(), image));
|
|
135
|
+
compactOldScreenshots(history);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
logger.info(`Agent stopped at max turns (${deps.maxTurns})`);
|
|
139
|
+
return { status: "max_turns", turns: deps.maxTurns, finalText, usage };
|
|
140
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
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
|
+
|
|
5
|
+
export interface SafetyDecision {
|
|
6
|
+
readonly decision: string;
|
|
7
|
+
readonly explanation: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function readSafetyDecision(args: Record<string, unknown>): SafetyDecision | undefined {
|
|
11
|
+
const raw = args.safety_decision;
|
|
12
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const record = raw as { decision?: unknown; explanation?: unknown };
|
|
17
|
+
return {
|
|
18
|
+
decision: typeof record.decision === "string" ? record.decision : "",
|
|
19
|
+
explanation: typeof record.explanation === "string" ? record.explanation : "",
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function isSafetyBlocked(decision: SafetyDecision | undefined): boolean {
|
|
24
|
+
return decision?.decision === "blocked";
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function requiresSafetyConfirmation(decision: SafetyDecision | undefined): boolean {
|
|
28
|
+
return decision?.decision === "require_confirmation";
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Fallback confirmer for the web UI when no interactive confirmer is wired up
|
|
33
|
+
* (e.g. tests, or callers that don't pass a per-request confirmer). Auto-approving
|
|
34
|
+
* here is NOT safe for real production traffic; startWebServer always supplies a
|
|
35
|
+
* real popup-backed confirmer per request, see createWebSafetyConfirmer in server.ts.
|
|
36
|
+
*/
|
|
37
|
+
export async function confirmSafetyForWeb(explanation: string, actionName: string): Promise<boolean> {
|
|
38
|
+
logger.info(
|
|
39
|
+
`Safety confirmation auto-approved (web fallback): ${actionName} - ${explanation || "No explanation provided"}`,
|
|
40
|
+
);
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export async function confirmSafetyInTerminal(explanation: string, actionName: string): Promise<boolean> {
|
|
45
|
+
if (!input.isTTY) {
|
|
46
|
+
logger.error("Safety confirmation required but stdin is not a TTY");
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const rl = readline.createInterface({ input, output });
|
|
51
|
+
try {
|
|
52
|
+
const answer = await rl.question(
|
|
53
|
+
`Safety confirmation required for ${actionName}: ${explanation || "No explanation provided"}\nProceed? [y/N] `,
|
|
54
|
+
);
|
|
55
|
+
return /^y(es)?$/i.test(answer.trim());
|
|
56
|
+
} finally {
|
|
57
|
+
rl.close();
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import { getLatestWebpPath } from "../playwright/processed.js";
|
|
3
|
+
|
|
4
|
+
export async function readWebpAsBase64(filePath: string): Promise<string> {
|
|
5
|
+
return fs.readFile(filePath, { encoding: "base64" });
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export async function loadLatestWebpBase64(
|
|
9
|
+
directory?: string,
|
|
10
|
+
): Promise<{ path: string; data: string }> {
|
|
11
|
+
const filePath = await getLatestWebpPath(directory);
|
|
12
|
+
if (!filePath) {
|
|
13
|
+
throw new Error("No processed webp screenshot found");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return {
|
|
17
|
+
path: filePath,
|
|
18
|
+
data: await readWebpAsBase64(filePath),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
|
|
5
|
+
export const SYSTEM_PROMPT_PATH = path.resolve(
|
|
6
|
+
path.dirname(fileURLToPath(import.meta.url)),
|
|
7
|
+
"../../files/system_prompt.txt",
|
|
8
|
+
);
|
|
9
|
+
|
|
10
|
+
export interface SystemPromptVars {
|
|
11
|
+
readonly os: string;
|
|
12
|
+
readonly displayWidth: number;
|
|
13
|
+
readonly displayHeight: number;
|
|
14
|
+
readonly keyboardLayout: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function osLabel(platform = process.platform): string {
|
|
18
|
+
if (platform === "darwin") {
|
|
19
|
+
return "Chromium on macOS";
|
|
20
|
+
}
|
|
21
|
+
if (platform === "win32") {
|
|
22
|
+
return "Chromium on Windows";
|
|
23
|
+
}
|
|
24
|
+
if (platform === "linux") {
|
|
25
|
+
return "Chromium on Linux";
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return `Chromium on ${platform}`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function defaultSystemPromptVars(
|
|
32
|
+
displayWidth: number,
|
|
33
|
+
displayHeight: number,
|
|
34
|
+
platform = process.platform,
|
|
35
|
+
locale = Intl.DateTimeFormat().resolvedOptions().locale,
|
|
36
|
+
): SystemPromptVars {
|
|
37
|
+
return {
|
|
38
|
+
os: osLabel(platform),
|
|
39
|
+
displayWidth,
|
|
40
|
+
displayHeight,
|
|
41
|
+
keyboardLayout: locale,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function renderSystemPrompt(template: string, vars: SystemPromptVars): string {
|
|
46
|
+
return template
|
|
47
|
+
.replaceAll("{{os}}", vars.os)
|
|
48
|
+
.replaceAll("{{display_width}}", String(vars.displayWidth))
|
|
49
|
+
.replaceAll("{{display_height}}", String(vars.displayHeight))
|
|
50
|
+
.replaceAll("{{keyboard_layout}}", vars.keyboardLayout)
|
|
51
|
+
.trim();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export async function loadSystemPrompt(
|
|
55
|
+
vars: SystemPromptVars,
|
|
56
|
+
filePath = SYSTEM_PROMPT_PATH,
|
|
57
|
+
): Promise<string> {
|
|
58
|
+
const template = await fs.readFile(filePath, "utf8");
|
|
59
|
+
const rendered = renderSystemPrompt(template, vars);
|
|
60
|
+
if (!rendered) {
|
|
61
|
+
throw new Error("system_prompt.txt is empty");
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return rendered;
|
|
65
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import type { TokenUsage } from "../shared/cost.js";
|
|
2
|
+
|
|
3
|
+
export const BROWSER_ACTION_NAMES = [
|
|
4
|
+
"click",
|
|
5
|
+
"double_click",
|
|
6
|
+
"triple_click",
|
|
7
|
+
"middle_click",
|
|
8
|
+
"right_click",
|
|
9
|
+
"mouse_down",
|
|
10
|
+
"mouse_up",
|
|
11
|
+
"move",
|
|
12
|
+
"type",
|
|
13
|
+
"drag_and_drop",
|
|
14
|
+
"wait",
|
|
15
|
+
"press_key",
|
|
16
|
+
"key_down",
|
|
17
|
+
"key_up",
|
|
18
|
+
"hotkey",
|
|
19
|
+
"take_screenshot",
|
|
20
|
+
"scroll",
|
|
21
|
+
"go_back",
|
|
22
|
+
"navigate",
|
|
23
|
+
"go_forward",
|
|
24
|
+
] as const;
|
|
25
|
+
|
|
26
|
+
export type BrowserActionName = (typeof BROWSER_ACTION_NAMES)[number];
|
|
27
|
+
|
|
28
|
+
export type MouseButton = "left" | "right" | "middle";
|
|
29
|
+
|
|
30
|
+
export interface ComputerUseMouse {
|
|
31
|
+
click(
|
|
32
|
+
x: number,
|
|
33
|
+
y: number,
|
|
34
|
+
options?: { button?: MouseButton; clickCount?: number },
|
|
35
|
+
): Promise<void>;
|
|
36
|
+
dblclick(x: number, y: number): Promise<void>;
|
|
37
|
+
move(x: number, y: number): Promise<void>;
|
|
38
|
+
down(): Promise<void>;
|
|
39
|
+
up(): Promise<void>;
|
|
40
|
+
wheel(deltaX: number, deltaY: number): Promise<void>;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface ComputerUseKeyboard {
|
|
44
|
+
type(text: string): Promise<void>;
|
|
45
|
+
press(key: string): Promise<void>;
|
|
46
|
+
down(key: string): Promise<void>;
|
|
47
|
+
up(key: string): Promise<void>;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface ComputerUsePage {
|
|
51
|
+
url(): string;
|
|
52
|
+
goto(url: string): Promise<unknown>;
|
|
53
|
+
goBack(): Promise<unknown>;
|
|
54
|
+
goForward(): Promise<unknown>;
|
|
55
|
+
mouse: ComputerUseMouse;
|
|
56
|
+
keyboard: ComputerUseKeyboard;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface ContentBlock {
|
|
60
|
+
type: string;
|
|
61
|
+
text?: string;
|
|
62
|
+
data?: string;
|
|
63
|
+
mime_type?: string;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface InteractionStep {
|
|
67
|
+
type: string;
|
|
68
|
+
id?: string;
|
|
69
|
+
name?: string;
|
|
70
|
+
call_id?: string;
|
|
71
|
+
arguments?: Record<string, unknown>;
|
|
72
|
+
content?: ContentBlock[];
|
|
73
|
+
result?: unknown;
|
|
74
|
+
is_error?: boolean;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface FunctionCallStep extends InteractionStep {
|
|
78
|
+
type: "function_call";
|
|
79
|
+
id: string;
|
|
80
|
+
name: string;
|
|
81
|
+
arguments: Record<string, unknown>;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface FunctionResultStep extends InteractionStep {
|
|
85
|
+
type: "function_result";
|
|
86
|
+
call_id: string;
|
|
87
|
+
name: string;
|
|
88
|
+
is_error?: boolean;
|
|
89
|
+
result: ContentBlock[];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export interface InteractionResponse {
|
|
93
|
+
steps: InteractionStep[];
|
|
94
|
+
usage?: TokenUsage;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export class AgentRunError extends Error {
|
|
98
|
+
constructor(
|
|
99
|
+
message: string,
|
|
100
|
+
readonly usage: TokenUsage,
|
|
101
|
+
) {
|
|
102
|
+
super(message);
|
|
103
|
+
this.name = "AgentRunError";
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export interface InteractionClient {
|
|
108
|
+
create(input: InteractionStep[]): Promise<InteractionResponse>;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export type ScreenshotSaver = (actionName: string) => Promise<string>;
|
|
112
|
+
export type SafetyConfirmer = (explanation: string, actionName: string) => Promise<boolean>;
|
|
113
|
+
export type Sleeper = (ms: number) => Promise<void>;
|
|
114
|
+
export type IntentListener = (label: string) => void | Promise<void>;
|
|
115
|
+
|
|
116
|
+
export interface ActionResult {
|
|
117
|
+
name: string;
|
|
118
|
+
callId: string;
|
|
119
|
+
payload: Record<string, unknown>;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export interface ExecuteTurnResult {
|
|
123
|
+
results: ActionResult[];
|
|
124
|
+
terminated: boolean;
|
|
125
|
+
lastScreenshotPath: string | undefined;
|
|
126
|
+
}
|