verybot 0.1.3
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.
Potentially problematic release.
This version of verybot might be problematic. Click here for more details.
- package/dist/brain/agent-registry.d.ts +75 -0
- package/dist/brain/agent-registry.js +124 -0
- package/dist/brain/agent.d.ts +146 -0
- package/dist/brain/agent.js +680 -0
- package/dist/brain/channel-store.d.ts +27 -0
- package/dist/brain/channel-store.js +78 -0
- package/dist/brain/compaction.d.ts +37 -0
- package/dist/brain/compaction.js +214 -0
- package/dist/brain/context.d.ts +33 -0
- package/dist/brain/context.js +77 -0
- package/dist/brain/delegation-store.d.ts +33 -0
- package/dist/brain/delegation-store.js +106 -0
- package/dist/brain/loop.d.ts +21 -0
- package/dist/brain/loop.js +161 -0
- package/dist/brain/mcp-adapter.d.ts +39 -0
- package/dist/brain/mcp-adapter.js +227 -0
- package/dist/brain/memory-extractor.d.ts +26 -0
- package/dist/brain/memory-extractor.js +82 -0
- package/dist/brain/providers.d.ts +10 -0
- package/dist/brain/providers.js +69 -0
- package/dist/brain/queue.d.ts +18 -0
- package/dist/brain/queue.js +84 -0
- package/dist/brain/run-tools.d.ts +47 -0
- package/dist/brain/run-tools.js +84 -0
- package/dist/brain/session-key.d.ts +23 -0
- package/dist/brain/session-key.js +41 -0
- package/dist/brain/session-state.d.ts +36 -0
- package/dist/brain/session-state.js +51 -0
- package/dist/brain/session-store.d.ts +50 -0
- package/dist/brain/session-store.js +207 -0
- package/dist/brain/session.d.ts +32 -0
- package/dist/brain/session.js +75 -0
- package/dist/brain/utils.d.ts +4 -0
- package/dist/brain/utils.js +26 -0
- package/dist/brain/worker-coordinator.d.ts +25 -0
- package/dist/brain/worker-coordinator.js +83 -0
- package/dist/channels/commands.d.ts +35 -0
- package/dist/channels/commands.js +65 -0
- package/dist/channels/discord/channel.d.ts +18 -0
- package/dist/channels/discord/channel.js +154 -0
- package/dist/channels/discord/markdown.d.ts +19 -0
- package/dist/channels/discord/markdown.js +62 -0
- package/dist/channels/manager.d.ts +29 -0
- package/dist/channels/manager.js +100 -0
- package/dist/channels/slack/channel.d.ts +26 -0
- package/dist/channels/slack/channel.js +207 -0
- package/dist/channels/slack/markdown.d.ts +19 -0
- package/dist/channels/slack/markdown.js +62 -0
- package/dist/channels/specs.d.ts +21 -0
- package/dist/channels/specs.js +96 -0
- package/dist/channels/telegram/channel.d.ts +18 -0
- package/dist/channels/telegram/channel.js +156 -0
- package/dist/channels/telegram/markdown.d.ts +17 -0
- package/dist/channels/telegram/markdown.js +66 -0
- package/dist/channels/types.d.ts +26 -0
- package/dist/channels/types.js +1 -0
- package/dist/channels/whatsapp/channel.d.ts +23 -0
- package/dist/channels/whatsapp/channel.js +242 -0
- package/dist/channels/whatsapp/markdown.d.ts +20 -0
- package/dist/channels/whatsapp/markdown.js +51 -0
- package/dist/cli/config.d.ts +5 -0
- package/dist/cli/config.js +78 -0
- package/dist/cli/index.d.ts +5 -0
- package/dist/cli/index.js +13 -0
- package/dist/computer/browser/actions.d.ts +31 -0
- package/dist/computer/browser/actions.js +148 -0
- package/dist/computer/browser/manager.d.ts +55 -0
- package/dist/computer/browser/manager.js +496 -0
- package/dist/computer/browser/profile-badge.d.ts +13 -0
- package/dist/computer/browser/profile-badge.js +67 -0
- package/dist/computer/browser/screenshot.d.ts +5 -0
- package/dist/computer/browser/screenshot.js +21 -0
- package/dist/computer/browser/snapshot.d.ts +30 -0
- package/dist/computer/browser/snapshot.js +242 -0
- package/dist/computer/browser/tools.d.ts +5 -0
- package/dist/computer/browser/tools.js +167 -0
- package/dist/computer/desktop/adapter.d.ts +25 -0
- package/dist/computer/desktop/adapter.js +11 -0
- package/dist/computer/desktop/macos.d.ts +24 -0
- package/dist/computer/desktop/macos.js +223 -0
- package/dist/computer/desktop/tools.d.ts +25 -0
- package/dist/computer/desktop/tools.js +114 -0
- package/dist/config/agent-config.d.ts +41 -0
- package/dist/config/agent-config.js +14 -0
- package/dist/config/model-catalog.d.ts +22 -0
- package/dist/config/model-catalog.js +99 -0
- package/dist/config/store.d.ts +25 -0
- package/dist/config/store.js +143 -0
- package/dist/config.d.ts +103 -0
- package/dist/config.js +224 -0
- package/dist/control-ui/assets/index-BANXNUyt.js +143 -0
- package/dist/control-ui/assets/index-BSUFrP9R.css +1 -0
- package/dist/control-ui/assets/noto-sans-cyrillic-ext-wght-normal-DSNfmdVt.woff2 +0 -0
- package/dist/control-ui/assets/noto-sans-cyrillic-wght-normal-B2hlT84T.woff2 +0 -0
- package/dist/control-ui/assets/noto-sans-devanagari-wght-normal-Cv-Vwajv.woff2 +0 -0
- package/dist/control-ui/assets/noto-sans-greek-ext-wght-normal-12T8GTDR.woff2 +0 -0
- package/dist/control-ui/assets/noto-sans-greek-wght-normal-Ymb6dZNd.woff2 +0 -0
- package/dist/control-ui/assets/noto-sans-latin-ext-wght-normal-W1qJv59z.woff2 +0 -0
- package/dist/control-ui/assets/noto-sans-latin-wght-normal-BYSzYMf3.woff2 +0 -0
- package/dist/control-ui/assets/noto-sans-vietnamese-wght-normal-DLTJy58D.woff2 +0 -0
- package/dist/control-ui/index.html +14 -0
- package/dist/control-ui/vite.svg +1 -0
- package/dist/events.d.ts +2 -0
- package/dist/events.js +11 -0
- package/dist/gateway/broadcast.d.ts +5 -0
- package/dist/gateway/broadcast.js +33 -0
- package/dist/gateway/methods/chat.d.ts +24 -0
- package/dist/gateway/methods/chat.js +19 -0
- package/dist/gateway/methods/config.d.ts +13 -0
- package/dist/gateway/methods/config.js +14 -0
- package/dist/gateway/methods/models.d.ts +10 -0
- package/dist/gateway/methods/models.js +14 -0
- package/dist/gateway/methods/prompt-templates.d.ts +23 -0
- package/dist/gateway/methods/prompt-templates.js +82 -0
- package/dist/gateway/methods/scheduler.d.ts +62 -0
- package/dist/gateway/methods/scheduler.js +129 -0
- package/dist/gateway/methods/sessions.d.ts +26 -0
- package/dist/gateway/methods/sessions.js +54 -0
- package/dist/gateway/methods/skills.d.ts +35 -0
- package/dist/gateway/methods/skills.js +202 -0
- package/dist/gateway/methods/system.d.ts +12 -0
- package/dist/gateway/methods/system.js +39 -0
- package/dist/gateway/methods/tasks.d.ts +21 -0
- package/dist/gateway/methods/tasks.js +46 -0
- package/dist/gateway/methods/teams.d.ts +70 -0
- package/dist/gateway/methods/teams.js +374 -0
- package/dist/gateway/methods/tools.d.ts +6 -0
- package/dist/gateway/methods/tools.js +7 -0
- package/dist/gateway/methods/whatsapp.d.ts +19 -0
- package/dist/gateway/methods/whatsapp.js +35 -0
- package/dist/gateway/rpc.d.ts +38 -0
- package/dist/gateway/rpc.js +75 -0
- package/dist/gateway/server.d.ts +4 -0
- package/dist/gateway/server.js +133 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +212 -0
- package/dist/integrations/github.d.ts +7 -0
- package/dist/integrations/github.js +133 -0
- package/dist/integrations/mcp.d.ts +7 -0
- package/dist/integrations/mcp.js +106 -0
- package/dist/integrations/registry.d.ts +43 -0
- package/dist/integrations/registry.js +258 -0
- package/dist/integrations/scanner.d.ts +10 -0
- package/dist/integrations/scanner.js +122 -0
- package/dist/integrations/twitter.d.ts +10 -0
- package/dist/integrations/twitter.js +120 -0
- package/dist/integrations/types.d.ts +72 -0
- package/dist/integrations/types.js +1 -0
- package/dist/logger.d.ts +16 -0
- package/dist/logger.js +104 -0
- package/dist/markdown/chunk.d.ts +9 -0
- package/dist/markdown/chunk.js +52 -0
- package/dist/markdown/ir.d.ts +37 -0
- package/dist/markdown/ir.js +529 -0
- package/dist/markdown/render.d.ts +22 -0
- package/dist/markdown/render.js +148 -0
- package/dist/markdown/table-render.d.ts +43 -0
- package/dist/markdown/table-render.js +219 -0
- package/dist/markdown/tables.d.ts +17 -0
- package/dist/markdown/tables.js +27 -0
- package/dist/memory/embedding.d.ts +16 -0
- package/dist/memory/embedding.js +66 -0
- package/dist/memory/extractor.d.ts +6 -0
- package/dist/memory/extractor.js +72 -0
- package/dist/memory/search.d.ts +15 -0
- package/dist/memory/search.js +57 -0
- package/dist/memory/store.d.ts +34 -0
- package/dist/memory/store.js +328 -0
- package/dist/memory/types.d.ts +9 -0
- package/dist/memory/types.js +2 -0
- package/dist/paths.d.ts +20 -0
- package/dist/paths.js +29 -0
- package/dist/prompt-templates/builtins.d.ts +2 -0
- package/dist/prompt-templates/builtins.js +72 -0
- package/dist/prompt-templates/store.d.ts +39 -0
- package/dist/prompt-templates/store.js +174 -0
- package/dist/prompt-templates/types.d.ts +10 -0
- package/dist/prompt-templates/types.js +1 -0
- package/dist/scheduler/connected-channels.d.ts +24 -0
- package/dist/scheduler/connected-channels.js +57 -0
- package/dist/scheduler/scheduler.d.ts +22 -0
- package/dist/scheduler/scheduler.js +132 -0
- package/dist/scheduler/store.d.ts +27 -0
- package/dist/scheduler/store.js +205 -0
- package/dist/scheduler/types.d.ts +29 -0
- package/dist/scheduler/types.js +1 -0
- package/dist/security/command-validator.d.ts +22 -0
- package/dist/security/command-validator.js +160 -0
- package/dist/security/docker-sandbox.d.ts +48 -0
- package/dist/security/docker-sandbox.js +218 -0
- package/dist/security/env-filter.d.ts +8 -0
- package/dist/security/env-filter.js +41 -0
- package/dist/skills/loader.d.ts +33 -0
- package/dist/skills/loader.js +132 -0
- package/dist/skills/prompt.d.ts +6 -0
- package/dist/skills/prompt.js +17 -0
- package/dist/skills/read-tool.d.ts +7 -0
- package/dist/skills/read-tool.js +24 -0
- package/dist/skills/scanner.d.ts +6 -0
- package/dist/skills/scanner.js +73 -0
- package/dist/skills/types.d.ts +15 -0
- package/dist/skills/types.js +1 -0
- package/dist/tasks/store.d.ts +47 -0
- package/dist/tasks/store.js +193 -0
- package/dist/tasks/types.d.ts +75 -0
- package/dist/tasks/types.js +32 -0
- package/dist/teams/store.d.ts +78 -0
- package/dist/teams/store.js +420 -0
- package/dist/teams/types.d.ts +23 -0
- package/dist/teams/types.js +1 -0
- package/dist/tools/bash.d.ts +16 -0
- package/dist/tools/bash.js +62 -0
- package/dist/tools/channel-history.d.ts +10 -0
- package/dist/tools/channel-history.js +43 -0
- package/dist/tools/delegate.d.ts +16 -0
- package/dist/tools/delegate.js +216 -0
- package/dist/tools/fs.d.ts +4 -0
- package/dist/tools/fs.js +335 -0
- package/dist/tools/integration-toggle.d.ts +14 -0
- package/dist/tools/integration-toggle.js +47 -0
- package/dist/tools/memory.d.ts +13 -0
- package/dist/tools/memory.js +65 -0
- package/dist/tools/registry.d.ts +6 -0
- package/dist/tools/registry.js +9 -0
- package/dist/tools/schedule.d.ts +8 -0
- package/dist/tools/schedule.js +219 -0
- package/dist/tools/speak.d.ts +10 -0
- package/dist/tools/speak.js +56 -0
- package/dist/tools/tasks.d.ts +29 -0
- package/dist/tools/tasks.js +92 -0
- package/dist/tools/teams.d.ts +7 -0
- package/dist/tools/teams.js +180 -0
- package/dist/tools/web-fetch.d.ts +3 -0
- package/dist/tools/web-fetch.js +22 -0
- package/dist/tts/edge.d.ts +10 -0
- package/dist/tts/edge.js +60 -0
- package/dist/tts/speak.d.ts +12 -0
- package/dist/tts/speak.js +81 -0
- package/dist/tts/transcribe.d.ts +5 -0
- package/dist/tts/transcribe.js +40 -0
- package/dist/utils.d.ts +5 -0
- package/dist/utils.js +22 -0
- package/package.json +90 -0
- package/verybot.js +2 -0
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parses Playwright's ariaSnapshot() output,
|
|
3
|
+
* assigns refs (e1, e2…) to interactive/content elements, and returns an
|
|
4
|
+
* annotated snapshot string plus a RoleRefMap for resolving refs back to locators.
|
|
5
|
+
*/
|
|
6
|
+
const INTERACTIVE_ROLES = new Set([
|
|
7
|
+
"button",
|
|
8
|
+
"link",
|
|
9
|
+
"textbox",
|
|
10
|
+
"checkbox",
|
|
11
|
+
"radio",
|
|
12
|
+
"combobox",
|
|
13
|
+
"listbox",
|
|
14
|
+
"menuitem",
|
|
15
|
+
"menuitemcheckbox",
|
|
16
|
+
"menuitemradio",
|
|
17
|
+
"option",
|
|
18
|
+
"searchbox",
|
|
19
|
+
"slider",
|
|
20
|
+
"spinbutton",
|
|
21
|
+
"switch",
|
|
22
|
+
"tab",
|
|
23
|
+
"treeitem",
|
|
24
|
+
]);
|
|
25
|
+
const CONTENT_ROLES = new Set([
|
|
26
|
+
"heading",
|
|
27
|
+
"cell",
|
|
28
|
+
"gridcell",
|
|
29
|
+
"columnheader",
|
|
30
|
+
"rowheader",
|
|
31
|
+
"listitem",
|
|
32
|
+
"article",
|
|
33
|
+
"region",
|
|
34
|
+
"main",
|
|
35
|
+
"navigation",
|
|
36
|
+
]);
|
|
37
|
+
const STRUCTURAL_ROLES = new Set([
|
|
38
|
+
"generic",
|
|
39
|
+
"group",
|
|
40
|
+
"list",
|
|
41
|
+
"table",
|
|
42
|
+
"row",
|
|
43
|
+
"rowgroup",
|
|
44
|
+
"grid",
|
|
45
|
+
"treegrid",
|
|
46
|
+
"menu",
|
|
47
|
+
"menubar",
|
|
48
|
+
"toolbar",
|
|
49
|
+
"tablist",
|
|
50
|
+
"tree",
|
|
51
|
+
"directory",
|
|
52
|
+
"document",
|
|
53
|
+
"application",
|
|
54
|
+
"presentation",
|
|
55
|
+
"none",
|
|
56
|
+
]);
|
|
57
|
+
function getIndentLevel(line) {
|
|
58
|
+
const match = line.match(/^(\s*)/);
|
|
59
|
+
return match ? Math.floor(match[1].length / 2) : 0;
|
|
60
|
+
}
|
|
61
|
+
function createRoleNameTracker() {
|
|
62
|
+
const counts = new Map();
|
|
63
|
+
const refsByKey = new Map();
|
|
64
|
+
return {
|
|
65
|
+
counts,
|
|
66
|
+
refsByKey,
|
|
67
|
+
getKey(role, name) {
|
|
68
|
+
return `${role}:${name ?? ""}`;
|
|
69
|
+
},
|
|
70
|
+
getNextIndex(role, name) {
|
|
71
|
+
const key = this.getKey(role, name);
|
|
72
|
+
const current = counts.get(key) ?? 0;
|
|
73
|
+
counts.set(key, current + 1);
|
|
74
|
+
return current;
|
|
75
|
+
},
|
|
76
|
+
trackRef(role, name, ref) {
|
|
77
|
+
const key = this.getKey(role, name);
|
|
78
|
+
const list = refsByKey.get(key) ?? [];
|
|
79
|
+
list.push(ref);
|
|
80
|
+
refsByKey.set(key, list);
|
|
81
|
+
},
|
|
82
|
+
getDuplicateKeys() {
|
|
83
|
+
const out = new Set();
|
|
84
|
+
for (const [key, refs] of refsByKey) {
|
|
85
|
+
if (refs.length > 1) {
|
|
86
|
+
out.add(key);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return out;
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function removeNthFromNonDuplicates(refs, tracker) {
|
|
94
|
+
const duplicates = tracker.getDuplicateKeys();
|
|
95
|
+
for (const [ref, data] of Object.entries(refs)) {
|
|
96
|
+
const key = tracker.getKey(data.role, data.name);
|
|
97
|
+
if (!duplicates.has(key)) {
|
|
98
|
+
delete refs[ref]?.nth;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
function compactTree(tree) {
|
|
103
|
+
const lines = tree.split("\n");
|
|
104
|
+
const result = [];
|
|
105
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
106
|
+
const line = lines[i];
|
|
107
|
+
if (line.includes("[ref=")) {
|
|
108
|
+
result.push(line);
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
if (line.includes(":") && !line.trimEnd().endsWith(":")) {
|
|
112
|
+
result.push(line);
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
const currentIndent = getIndentLevel(line);
|
|
116
|
+
let hasRelevantChildren = false;
|
|
117
|
+
for (let j = i + 1; j < lines.length; j += 1) {
|
|
118
|
+
const childIndent = getIndentLevel(lines[j]);
|
|
119
|
+
if (childIndent <= currentIndent)
|
|
120
|
+
break;
|
|
121
|
+
if (lines[j]?.includes("[ref=")) {
|
|
122
|
+
hasRelevantChildren = true;
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (hasRelevantChildren) {
|
|
127
|
+
result.push(line);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return result.join("\n");
|
|
131
|
+
}
|
|
132
|
+
function processLine(line, refs, options, tracker, nextRef) {
|
|
133
|
+
const depth = getIndentLevel(line);
|
|
134
|
+
if (options.maxDepth !== undefined && depth > options.maxDepth) {
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
const match = line.match(/^(\s*-\s*)(\w+)(?:\s+"([^"]*)")?(.*)$/);
|
|
138
|
+
if (!match) {
|
|
139
|
+
return options.interactive ? null : line;
|
|
140
|
+
}
|
|
141
|
+
const [, prefix, roleRaw, name, suffix] = match;
|
|
142
|
+
if (roleRaw.startsWith("/")) {
|
|
143
|
+
return options.interactive ? null : line;
|
|
144
|
+
}
|
|
145
|
+
const role = roleRaw.toLowerCase();
|
|
146
|
+
const isInteractive = INTERACTIVE_ROLES.has(role);
|
|
147
|
+
const isContent = CONTENT_ROLES.has(role);
|
|
148
|
+
const isStructural = STRUCTURAL_ROLES.has(role);
|
|
149
|
+
if (options.interactive && !isInteractive)
|
|
150
|
+
return null;
|
|
151
|
+
if (options.compact && isStructural && !name)
|
|
152
|
+
return null;
|
|
153
|
+
const shouldHaveRef = isInteractive || (isContent && name);
|
|
154
|
+
if (!shouldHaveRef)
|
|
155
|
+
return line;
|
|
156
|
+
const ref = nextRef();
|
|
157
|
+
const nth = tracker.getNextIndex(role, name);
|
|
158
|
+
tracker.trackRef(role, name, ref);
|
|
159
|
+
refs[ref] = { role, name, nth };
|
|
160
|
+
let enhanced = `${prefix}${roleRaw}`;
|
|
161
|
+
if (name)
|
|
162
|
+
enhanced += ` "${name}"`;
|
|
163
|
+
enhanced += ` [ref=${ref}]`;
|
|
164
|
+
if (nth > 0)
|
|
165
|
+
enhanced += ` [nth=${nth}]`;
|
|
166
|
+
if (suffix)
|
|
167
|
+
enhanced += suffix;
|
|
168
|
+
return enhanced;
|
|
169
|
+
}
|
|
170
|
+
/** Validate and normalize a ref string like "e5", "@e5", or "ref=e5". Returns null if invalid. */
|
|
171
|
+
export function parseRoleRef(raw) {
|
|
172
|
+
const trimmed = raw.trim();
|
|
173
|
+
if (!trimmed)
|
|
174
|
+
return null;
|
|
175
|
+
const normalized = trimmed.startsWith("@")
|
|
176
|
+
? trimmed.slice(1)
|
|
177
|
+
: trimmed.startsWith("ref=")
|
|
178
|
+
? trimmed.slice(4)
|
|
179
|
+
: trimmed;
|
|
180
|
+
return /^e\d+$/.test(normalized) ? normalized : null;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Parse Playwright's `ariaSnapshot()` text, assign refs to interactive/content
|
|
184
|
+
* elements, and return the annotated snapshot + a map from ref → role info.
|
|
185
|
+
*/
|
|
186
|
+
export function buildRoleSnapshotFromAriaSnapshot(ariaSnapshot, options = {}) {
|
|
187
|
+
const lines = ariaSnapshot.split("\n");
|
|
188
|
+
const refs = {};
|
|
189
|
+
const tracker = createRoleNameTracker();
|
|
190
|
+
let counter = 0;
|
|
191
|
+
const nextRef = () => {
|
|
192
|
+
counter += 1;
|
|
193
|
+
return `e${counter}`;
|
|
194
|
+
};
|
|
195
|
+
if (options.interactive) {
|
|
196
|
+
const result = [];
|
|
197
|
+
for (const line of lines) {
|
|
198
|
+
const depth = getIndentLevel(line);
|
|
199
|
+
if (options.maxDepth !== undefined && depth > options.maxDepth)
|
|
200
|
+
continue;
|
|
201
|
+
const match = line.match(/^(\s*-\s*)(\w+)(?:\s+"([^"]*)")?(.*)$/);
|
|
202
|
+
if (!match)
|
|
203
|
+
continue;
|
|
204
|
+
const [, , roleRaw, name, suffix] = match;
|
|
205
|
+
if (roleRaw.startsWith("/"))
|
|
206
|
+
continue;
|
|
207
|
+
const role = roleRaw.toLowerCase();
|
|
208
|
+
if (!INTERACTIVE_ROLES.has(role))
|
|
209
|
+
continue;
|
|
210
|
+
const ref = nextRef();
|
|
211
|
+
const nth = tracker.getNextIndex(role, name);
|
|
212
|
+
tracker.trackRef(role, name, ref);
|
|
213
|
+
refs[ref] = { role, name, nth };
|
|
214
|
+
let enhanced = `- ${roleRaw}`;
|
|
215
|
+
if (name)
|
|
216
|
+
enhanced += ` "${name}"`;
|
|
217
|
+
enhanced += ` [ref=${ref}]`;
|
|
218
|
+
if (nth > 0)
|
|
219
|
+
enhanced += ` [nth=${nth}]`;
|
|
220
|
+
if (suffix.includes("["))
|
|
221
|
+
enhanced += suffix;
|
|
222
|
+
result.push(enhanced);
|
|
223
|
+
}
|
|
224
|
+
removeNthFromNonDuplicates(refs, tracker);
|
|
225
|
+
return {
|
|
226
|
+
snapshot: result.join("\n") || "(no interactive elements)",
|
|
227
|
+
refs,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
const result = [];
|
|
231
|
+
for (const line of lines) {
|
|
232
|
+
const processed = processLine(line, refs, options, tracker, nextRef);
|
|
233
|
+
if (processed !== null)
|
|
234
|
+
result.push(processed);
|
|
235
|
+
}
|
|
236
|
+
removeNthFromNonDuplicates(refs, tracker);
|
|
237
|
+
const tree = result.join("\n") || "(empty)";
|
|
238
|
+
return {
|
|
239
|
+
snapshot: options.compact ? compactTree(tree) : tree,
|
|
240
|
+
refs,
|
|
241
|
+
};
|
|
242
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type ToolSet } from "ai";
|
|
2
|
+
import type { BrowserManager } from "./manager.js";
|
|
3
|
+
/** Tool names exported for delegate.ts to strip/replace per-worker instances. */
|
|
4
|
+
export declare const BROWSER_TOOL_NAMES: string[];
|
|
5
|
+
export declare function createBrowserTools(browser: BrowserManager): ToolSet;
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { tool } from "ai";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { parseRoleRef } from "./snapshot.js";
|
|
4
|
+
import * as actions from "./actions.js";
|
|
5
|
+
/** Tool names exported for delegate.ts to strip/replace per-worker instances. */
|
|
6
|
+
export const BROWSER_TOOL_NAMES = [
|
|
7
|
+
"browser_navigate",
|
|
8
|
+
"browser_snapshot",
|
|
9
|
+
"browser_click",
|
|
10
|
+
"browser_type",
|
|
11
|
+
"browser_press_key",
|
|
12
|
+
"browser_screenshot",
|
|
13
|
+
"browser_close",
|
|
14
|
+
"browser_switch_profile",
|
|
15
|
+
];
|
|
16
|
+
export function createBrowserTools(browser) {
|
|
17
|
+
return {
|
|
18
|
+
browser_navigate: tool({
|
|
19
|
+
description: "Navigate the browser to a URL. Launches the browser if not already open. " +
|
|
20
|
+
"Returns the page title, URL, and an accessibility snapshot with element refs (e1, e2…).",
|
|
21
|
+
inputSchema: z.object({
|
|
22
|
+
url: z.string().url().describe("The URL to navigate to"),
|
|
23
|
+
}),
|
|
24
|
+
execute: async ({ url }) => {
|
|
25
|
+
try {
|
|
26
|
+
return await actions.navigate(browser, url);
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
return actions.toAIFriendlyError(err);
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
}),
|
|
33
|
+
browser_snapshot: tool({
|
|
34
|
+
description: "Take an accessibility snapshot of the current page. Returns the page structure " +
|
|
35
|
+
"with interactive elements labeled with refs (e1, e2…). Use these refs with " +
|
|
36
|
+
"browser_click and browser_type. Always take a fresh snapshot after page changes.",
|
|
37
|
+
inputSchema: z.object({}),
|
|
38
|
+
execute: async () => {
|
|
39
|
+
try {
|
|
40
|
+
const snapshot = await actions.takeSnapshot(browser);
|
|
41
|
+
return actions.withProfilePrefix(browser, snapshot);
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
return actions.toAIFriendlyError(err);
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
}),
|
|
48
|
+
browser_click: tool({
|
|
49
|
+
description: "Click an element by its ref from the latest snapshot (e.g. 'e5'). " +
|
|
50
|
+
"Automatically takes a new snapshot after clicking so you can see the result.",
|
|
51
|
+
inputSchema: z.object({
|
|
52
|
+
ref: z.string().describe("Element ref from snapshot, e.g. 'e5'"),
|
|
53
|
+
}),
|
|
54
|
+
execute: async ({ ref }) => {
|
|
55
|
+
const parsed = parseRoleRef(ref);
|
|
56
|
+
if (!parsed)
|
|
57
|
+
return `Invalid ref "${ref}". Use a ref like "e5" from the latest snapshot.`;
|
|
58
|
+
try {
|
|
59
|
+
return await actions.click(browser, parsed);
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
return actions.toAIFriendlyError(err);
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
}),
|
|
66
|
+
browser_type: tool({
|
|
67
|
+
description: "Type text into an input field by its ref from the latest snapshot. " +
|
|
68
|
+
"Clears existing content first (like a user selecting all and typing). " +
|
|
69
|
+
"Set submit=true to press Enter after typing (e.g. for search forms).",
|
|
70
|
+
inputSchema: z.object({
|
|
71
|
+
ref: z.string().describe("Element ref from snapshot, e.g. 'e3'"),
|
|
72
|
+
text: z.string().describe("Text to type into the field"),
|
|
73
|
+
submit: z.boolean().optional().describe("Press Enter after typing (default: false)"),
|
|
74
|
+
}),
|
|
75
|
+
execute: async ({ ref, text, submit }) => {
|
|
76
|
+
const parsed = parseRoleRef(ref);
|
|
77
|
+
if (!parsed)
|
|
78
|
+
return `Invalid ref "${ref}". Use a ref like "e3" from the latest snapshot.`;
|
|
79
|
+
try {
|
|
80
|
+
return await actions.type(browser, parsed, text, submit);
|
|
81
|
+
}
|
|
82
|
+
catch (err) {
|
|
83
|
+
return actions.toAIFriendlyError(err);
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
}),
|
|
87
|
+
browser_press_key: tool({
|
|
88
|
+
description: "Press a keyboard key or combination. Examples: 'Enter', 'Escape', " +
|
|
89
|
+
"'ArrowDown', 'Control+A', 'Meta+C'. Use for keyboard shortcuts and navigation.",
|
|
90
|
+
inputSchema: z.object({
|
|
91
|
+
key: z.string().describe("Key or combination to press, e.g. 'Enter' or 'Control+A'"),
|
|
92
|
+
}),
|
|
93
|
+
execute: async ({ key }) => {
|
|
94
|
+
try {
|
|
95
|
+
return await actions.pressKey(browser, key);
|
|
96
|
+
}
|
|
97
|
+
catch (err) {
|
|
98
|
+
return actions.toAIFriendlyError(err);
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
}),
|
|
102
|
+
browser_screenshot: tool({
|
|
103
|
+
description: "Take a screenshot of the current page for visual inspection. " +
|
|
104
|
+
"Returns an image. Use when you need to see the visual layout, " +
|
|
105
|
+
"verify visual changes, or debug rendering issues.",
|
|
106
|
+
inputSchema: z.object({
|
|
107
|
+
fullPage: z.boolean().optional().describe("Capture the full scrollable page (default: false, viewport only)"),
|
|
108
|
+
}),
|
|
109
|
+
execute: async ({ fullPage }) => {
|
|
110
|
+
try {
|
|
111
|
+
const { base64, mediaType } = await actions.takeScreenshot(browser, fullPage);
|
|
112
|
+
return { base64, mediaType };
|
|
113
|
+
}
|
|
114
|
+
catch (err) {
|
|
115
|
+
return actions.toAIFriendlyError(err);
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
toModelOutput({ output }) {
|
|
119
|
+
if (typeof output === "object" && output !== null && "base64" in output) {
|
|
120
|
+
const { base64, mediaType } = output;
|
|
121
|
+
return {
|
|
122
|
+
type: "content",
|
|
123
|
+
value: [
|
|
124
|
+
{
|
|
125
|
+
type: "image-data",
|
|
126
|
+
data: base64,
|
|
127
|
+
mediaType,
|
|
128
|
+
},
|
|
129
|
+
],
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
return { type: "text", value: String(output) };
|
|
133
|
+
},
|
|
134
|
+
}),
|
|
135
|
+
browser_switch_profile: tool({
|
|
136
|
+
description: "Switch the browser to a different named profile. Each profile has its own " +
|
|
137
|
+
"cookies, login state, and extensions. Closes the current browser — it will " +
|
|
138
|
+
"relaunch with the new profile on the next navigation. " +
|
|
139
|
+
"Profile names: letters, digits, and hyphens only (e.g. 'work', 'personal').",
|
|
140
|
+
inputSchema: z.object({
|
|
141
|
+
profile: z.string().describe("Profile name to switch to, e.g. 'work' or 'personal'"),
|
|
142
|
+
}),
|
|
143
|
+
execute: async ({ profile }) => {
|
|
144
|
+
try {
|
|
145
|
+
return await actions.switchProfile(browser, profile);
|
|
146
|
+
}
|
|
147
|
+
catch (err) {
|
|
148
|
+
return actions.toAIFriendlyError(err);
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
}),
|
|
152
|
+
browser_close: tool({
|
|
153
|
+
description: "Close the browser. Use when done with browser tasks.",
|
|
154
|
+
inputSchema: z.object({}),
|
|
155
|
+
execute: async () => {
|
|
156
|
+
try {
|
|
157
|
+
const profile = browser.getActiveProfile();
|
|
158
|
+
await browser.close();
|
|
159
|
+
return `[profile: ${profile}] Browser closed.`;
|
|
160
|
+
}
|
|
161
|
+
catch (err) {
|
|
162
|
+
return actions.toAIFriendlyError(err);
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
}),
|
|
166
|
+
};
|
|
167
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface ScreenInfo {
|
|
2
|
+
/** Screenshot pixel width (retina resolution). */
|
|
3
|
+
widthPx: number;
|
|
4
|
+
/** Screenshot pixel height (retina resolution). */
|
|
5
|
+
heightPx: number;
|
|
6
|
+
/** Retina scale factor (1 for non-retina, 2 for retina). */
|
|
7
|
+
scaleFactor: number;
|
|
8
|
+
}
|
|
9
|
+
export interface DesktopAdapter {
|
|
10
|
+
getScreenInfo(): ScreenInfo;
|
|
11
|
+
screenshot(): Promise<Buffer>;
|
|
12
|
+
click(x: number, y: number): Promise<void>;
|
|
13
|
+
doubleClick(x: number, y: number): Promise<void>;
|
|
14
|
+
rightClick(x: number, y: number): Promise<void>;
|
|
15
|
+
middleClick(x: number, y: number): Promise<void>;
|
|
16
|
+
tripleClick(x: number, y: number): Promise<void>;
|
|
17
|
+
mouseMove(x: number, y: number): Promise<void>;
|
|
18
|
+
type(text: string): Promise<void>;
|
|
19
|
+
/** Press a key or key combination (xdotool syntax, e.g. "Return", "ctrl+s"). */
|
|
20
|
+
key(combo: string): Promise<void>;
|
|
21
|
+
scroll(x: number, y: number, direction: "up" | "down" | "left" | "right", amount: number): Promise<void>;
|
|
22
|
+
getCursorPosition(): Promise<[number, number]>;
|
|
23
|
+
dragTo(startX: number, startY: number, endX: number, endY: number): Promise<void>;
|
|
24
|
+
}
|
|
25
|
+
export declare function createDesktopAdapter(): Promise<DesktopAdapter>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export async function createDesktopAdapter() {
|
|
2
|
+
switch (process.platform) {
|
|
3
|
+
case "darwin": {
|
|
4
|
+
const { MacOSAdapter } = await import("./macos.js");
|
|
5
|
+
return new MacOSAdapter();
|
|
6
|
+
}
|
|
7
|
+
default:
|
|
8
|
+
throw new Error(`Desktop control is not yet supported on ${process.platform}. ` +
|
|
9
|
+
`Currently supported: macOS (darwin).`);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { DesktopAdapter, ScreenInfo } from "./adapter.js";
|
|
2
|
+
export declare class MacOSAdapter implements DesktopAdapter {
|
|
3
|
+
private screenInfo;
|
|
4
|
+
constructor();
|
|
5
|
+
getScreenInfo(): ScreenInfo;
|
|
6
|
+
screenshot(): Promise<Buffer>;
|
|
7
|
+
click(x: number, y: number): Promise<void>;
|
|
8
|
+
doubleClick(x: number, y: number): Promise<void>;
|
|
9
|
+
rightClick(x: number, y: number): Promise<void>;
|
|
10
|
+
middleClick(x: number, y: number): Promise<void>;
|
|
11
|
+
tripleClick(x: number, y: number): Promise<void>;
|
|
12
|
+
mouseMove(x: number, y: number): Promise<void>;
|
|
13
|
+
type(text: string): Promise<void>;
|
|
14
|
+
key(combo: string): Promise<void>;
|
|
15
|
+
scroll(x: number, y: number, direction: "up" | "down" | "left" | "right", amount: number): Promise<void>;
|
|
16
|
+
getCursorPosition(): Promise<[number, number]>;
|
|
17
|
+
dragTo(startX: number, startY: number, endX: number, endY: number): Promise<void>;
|
|
18
|
+
private checkDependencies;
|
|
19
|
+
private detectScreenInfo;
|
|
20
|
+
/** Convert pixel coordinates to logical (point) coordinates for cliclick. */
|
|
21
|
+
private toLogical;
|
|
22
|
+
/** Run cliclick with the given action arguments. */
|
|
23
|
+
private cliclick;
|
|
24
|
+
}
|