@akshayram1/omnibrowser-agent 0.2.32 → 0.3.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/.env +1 -0
- package/README.github.md +37 -0
- package/demo1.gif +0 -0
- package/dist/background.js +1 -1
- package/dist/background.js.map +1 -1
- package/dist/content.js +63 -15
- package/dist/content.js.map +3 -3
- package/dist/lib.js +103 -19
- package/dist/lib.js.map +3 -3
- package/dist/manifest.json +1 -1
- package/dist/types/lib/index.d.ts +1 -0
- package/dist/types/shared/contracts.d.ts +2 -0
- package/dist/types/shared/parse-action.d.ts +1 -0
- package/dist/types/shared/safety.d.ts +2 -2
- package/icons/big.png +0 -0
- package/icons/logo.png +0 -0
- package/icons/logo_horizontal.png +0 -0
- package/notebook/.env +1 -0
- package/notebook/README.md +39 -0
- package/notebook/custom_quantized_llm_colab copy.ipynb +7084 -0
- package/notebook/data/omnibrowser_planner_train.jsonl +500 -0
- package/package.json +1 -1
package/dist/lib.js
CHANGED
|
@@ -11,6 +11,7 @@ var __export = (target, all) => {
|
|
|
11
11
|
// src/shared/parse-action.ts
|
|
12
12
|
var parse_action_exports = {};
|
|
13
13
|
__export(parse_action_exports, {
|
|
14
|
+
PARSE_FAILURE_PATTERN: () => PARSE_FAILURE_PATTERN,
|
|
14
15
|
parseAction: () => parseAction,
|
|
15
16
|
parsePlannerResult: () => parsePlannerResult
|
|
16
17
|
});
|
|
@@ -66,6 +67,28 @@ function parseAction(raw) {
|
|
|
66
67
|
if (typeof obj.type !== "string" || !VALID_TYPES.has(obj.type)) {
|
|
67
68
|
return { type: "done", reason: `Unknown or missing action type: ${String(obj.type)}` };
|
|
68
69
|
}
|
|
70
|
+
const t = obj.type;
|
|
71
|
+
if ((t === "click" || t === "type" || t === "extract" || t === "focus") && typeof obj.selector !== "string") {
|
|
72
|
+
return { type: "done", reason: `Missing required field 'selector' for action type: ${t}` };
|
|
73
|
+
}
|
|
74
|
+
if (t === "extract" && typeof obj.label !== "string") {
|
|
75
|
+
return { type: "done", reason: `Missing required field 'label' for action type: extract` };
|
|
76
|
+
}
|
|
77
|
+
if (t === "type" && typeof obj.text !== "string") {
|
|
78
|
+
return { type: "done", reason: `Missing required field 'text' for action type: type` };
|
|
79
|
+
}
|
|
80
|
+
if (t === "navigate" && typeof obj.url !== "string") {
|
|
81
|
+
return { type: "done", reason: `Missing required field 'url' for action type: navigate` };
|
|
82
|
+
}
|
|
83
|
+
if (t === "scroll" && typeof obj.deltaY !== "number") {
|
|
84
|
+
return { type: "done", reason: `Missing required field 'deltaY' for action type: scroll` };
|
|
85
|
+
}
|
|
86
|
+
if (t === "wait" && typeof obj.ms !== "number") {
|
|
87
|
+
return { type: "done", reason: `Missing required field 'ms' for action type: wait` };
|
|
88
|
+
}
|
|
89
|
+
if (t === "done" && typeof obj.reason !== "string") {
|
|
90
|
+
return { type: "done", reason: `Missing required field 'reason' for action type: done` };
|
|
91
|
+
}
|
|
69
92
|
return obj;
|
|
70
93
|
}
|
|
71
94
|
function parsePlannerResult(raw) {
|
|
@@ -96,10 +119,11 @@ function parsePlannerResult(raw) {
|
|
|
96
119
|
}
|
|
97
120
|
return { action: parseAction(jsonStr) };
|
|
98
121
|
}
|
|
99
|
-
var VALID_TYPES;
|
|
122
|
+
var PARSE_FAILURE_PATTERN, VALID_TYPES;
|
|
100
123
|
var init_parse_action = __esm({
|
|
101
124
|
"src/shared/parse-action.ts"() {
|
|
102
125
|
"use strict";
|
|
126
|
+
PARSE_FAILURE_PATTERN = /(No JSON|JSON parse error|Parsed value is not an object|Unknown or missing action type|Missing required field)/;
|
|
103
127
|
VALID_TYPES = /* @__PURE__ */ new Set([
|
|
104
128
|
"click",
|
|
105
129
|
"type",
|
|
@@ -150,6 +174,9 @@ async function executeAction(action) {
|
|
|
150
174
|
}
|
|
151
175
|
case "type": {
|
|
152
176
|
const input = mustFind(action.selector);
|
|
177
|
+
if (input.value === action.text) {
|
|
178
|
+
return `Already contains correct value in ${action.selector}`;
|
|
179
|
+
}
|
|
153
180
|
input.focus();
|
|
154
181
|
if (action.clearFirst) {
|
|
155
182
|
input.value = "";
|
|
@@ -253,8 +280,8 @@ function cssPath(element) {
|
|
|
253
280
|
return parts.join(" > ");
|
|
254
281
|
}
|
|
255
282
|
function isVisible(el) {
|
|
256
|
-
if (el.offsetParent === null && el.tagName !== "BODY") return false;
|
|
257
283
|
const style = window.getComputedStyle(el);
|
|
284
|
+
if (el.offsetParent === null && el.tagName !== "BODY" && style.position !== "fixed") return false;
|
|
258
285
|
if (style.display === "none" || style.visibility === "hidden" || style.opacity === "0") return false;
|
|
259
286
|
const rect = el.getBoundingClientRect();
|
|
260
287
|
return rect.width > 0 || rect.height > 0;
|
|
@@ -263,6 +290,14 @@ function isInViewport(el) {
|
|
|
263
290
|
const rect = el.getBoundingClientRect();
|
|
264
291
|
return rect.bottom > 0 && rect.top < window.innerHeight && rect.right > 0 && rect.left < window.innerWidth;
|
|
265
292
|
}
|
|
293
|
+
function isActiveElement(el) {
|
|
294
|
+
if (el.classList.contains("active")) return true;
|
|
295
|
+
if (el.getAttribute("aria-selected") === "true") return true;
|
|
296
|
+
const ariaCurrent = el.getAttribute("aria-current");
|
|
297
|
+
if (ariaCurrent && ariaCurrent !== "false") return true;
|
|
298
|
+
if (el.getAttribute("aria-pressed") === "true") return true;
|
|
299
|
+
return false;
|
|
300
|
+
}
|
|
266
301
|
function getAssociatedLabel(el) {
|
|
267
302
|
if (el.id) {
|
|
268
303
|
const label = document.querySelector(`label[for="${CSS.escape(el.id)}"]`);
|
|
@@ -284,7 +319,7 @@ function getAssociatedLabel(el) {
|
|
|
284
319
|
function collectSnapshot() {
|
|
285
320
|
const allNodes = Array.from(
|
|
286
321
|
document.querySelectorAll(CANDIDATE_SELECTOR)
|
|
287
|
-
).filter(isVisible);
|
|
322
|
+
).filter(isVisible).filter((el) => !el.closest("[data-agent-exclude]"));
|
|
288
323
|
const inView = allNodes.filter(isInViewport);
|
|
289
324
|
const offScreen = allNodes.filter((el) => !isInViewport(el));
|
|
290
325
|
const nodes = [...inView, ...offScreen].slice(0, MAX_CANDIDATES);
|
|
@@ -296,7 +331,8 @@ function collectSnapshot() {
|
|
|
296
331
|
role: node.getAttribute("role") ?? node.tagName.toLowerCase(),
|
|
297
332
|
text: (node.innerText || node.getAttribute("name") || "").trim().slice(0, 120),
|
|
298
333
|
placeholder: placeholder || void 0,
|
|
299
|
-
label: associatedLabel || void 0
|
|
334
|
+
label: associatedLabel || void 0,
|
|
335
|
+
active: isActiveElement(node) || void 0
|
|
300
336
|
};
|
|
301
337
|
});
|
|
302
338
|
const textPreview = document.body.innerText.replace(/\s+/g, " ").trim().slice(0, 1500);
|
|
@@ -375,14 +411,15 @@ function toPlannerResult(raw) {
|
|
|
375
411
|
return { action: raw };
|
|
376
412
|
}
|
|
377
413
|
async function parsePlannerText(raw) {
|
|
378
|
-
const
|
|
379
|
-
|
|
414
|
+
const { parsePlannerResult: parsePlannerResult2, PARSE_FAILURE_PATTERN: PARSE_FAILURE_PATTERN2 } = await Promise.resolve().then(() => (init_parse_action(), parse_action_exports));
|
|
415
|
+
const result = parsePlannerResult2(raw);
|
|
416
|
+
const parseFailed = result.action.type === "done" && PARSE_FAILURE_PATTERN2.test(result.action.reason);
|
|
417
|
+
return { result, parseFailed };
|
|
380
418
|
}
|
|
381
419
|
async function normalizeBridgeResponse(raw) {
|
|
382
420
|
if (typeof raw === "string") {
|
|
383
|
-
const
|
|
384
|
-
|
|
385
|
-
return { result: parsed, parseFailed, rawText: raw };
|
|
421
|
+
const { result, parseFailed } = await parsePlannerText(raw);
|
|
422
|
+
return { result, parseFailed, rawText: raw };
|
|
386
423
|
}
|
|
387
424
|
return { result: toPlannerResult(raw), parseFailed: false };
|
|
388
425
|
}
|
|
@@ -425,9 +462,16 @@ var RISKY_KEYWORDS = /\b(delete|remove|pay|purchase|submit|confirm|checkout|tran
|
|
|
425
462
|
function elementTextRisky(text) {
|
|
426
463
|
return text != null && RISKY_KEYWORDS.test(text);
|
|
427
464
|
}
|
|
428
|
-
function
|
|
465
|
+
function candidateText(selector, candidates) {
|
|
466
|
+
const match = candidates?.find((c) => c.selector === selector);
|
|
467
|
+
return match ? [match.label, match.text, match.placeholder].filter(Boolean).join(" ") || void 0 : void 0;
|
|
468
|
+
}
|
|
469
|
+
function assessRisk(action, candidates) {
|
|
429
470
|
switch (action.type) {
|
|
430
471
|
case "navigate": {
|
|
472
|
+
if (action.url.startsWith("#") || action.url.startsWith("/") || action.url.startsWith("./") || action.url.startsWith("../")) {
|
|
473
|
+
return "safe";
|
|
474
|
+
}
|
|
431
475
|
try {
|
|
432
476
|
const next = new URL(action.url);
|
|
433
477
|
if (!["http:", "https:"].includes(next.protocol)) {
|
|
@@ -438,10 +482,14 @@ function assessRisk(action) {
|
|
|
438
482
|
}
|
|
439
483
|
return "safe";
|
|
440
484
|
}
|
|
441
|
-
case "click":
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
485
|
+
case "click": {
|
|
486
|
+
const text = action.label ?? candidateText(action.selector, candidates) ?? action.selector;
|
|
487
|
+
return elementTextRisky(text) ? "review" : "safe";
|
|
488
|
+
}
|
|
489
|
+
case "type": {
|
|
490
|
+
const text = action.label ?? candidateText(action.selector, candidates) ?? action.selector;
|
|
491
|
+
return elementTextRisky(text) ? "review" : "safe";
|
|
492
|
+
}
|
|
445
493
|
case "focus":
|
|
446
494
|
case "scroll":
|
|
447
495
|
case "wait":
|
|
@@ -481,7 +529,14 @@ var DEFAULT_SYSTEM_PROMPT = [
|
|
|
481
529
|
"",
|
|
482
530
|
"IMPORTANT: You MUST use selectors exactly as listed in the candidates. NEVER invent or guess selectors.",
|
|
483
531
|
"If you cannot find a matching candidate for a target element, use the closest match from the candidates list.",
|
|
484
|
-
"When previous step failed, recover by trying a different candidate selector or fallback strategy."
|
|
532
|
+
"When previous step failed, recover by trying a different candidate selector or fallback strategy.",
|
|
533
|
+
"NEVER use navigate for in-page tab switches or buttons \u2014 use click with the button's selector instead.",
|
|
534
|
+
"",
|
|
535
|
+
"Loop prevention rules (CRITICAL):",
|
|
536
|
+
"- If a candidate shows 'state: active', it is already selected/active \u2014 do NOT click it again.",
|
|
537
|
+
"- Check the History before acting. If the same selector was already clicked or typed in a recent step, do NOT repeat it \u2014 proceed to the next logical step or return done.",
|
|
538
|
+
"- If the goal is already achieved (value is set, element clicked, task complete), return done immediately.",
|
|
539
|
+
"- NEVER click a navigation tab or button more than once per goal unless the page changed to a different section."
|
|
485
540
|
].join("\n");
|
|
486
541
|
function formatCandidate(candidate, index) {
|
|
487
542
|
const parts = [
|
|
@@ -495,6 +550,9 @@ function formatCandidate(candidate, index) {
|
|
|
495
550
|
if (candidate.placeholder) {
|
|
496
551
|
parts.push(`placeholder: ${JSON.stringify(candidate.placeholder)}`);
|
|
497
552
|
}
|
|
553
|
+
if (candidate.active) {
|
|
554
|
+
parts.push(`state: active`);
|
|
555
|
+
}
|
|
498
556
|
return `[${index + 1}] ${parts.join(" | ")}`;
|
|
499
557
|
}
|
|
500
558
|
function buildSystemPrompt(customPrompt) {
|
|
@@ -545,7 +603,7 @@ function isParseFailure(result) {
|
|
|
545
603
|
return false;
|
|
546
604
|
}
|
|
547
605
|
const reason = result.action.reason;
|
|
548
|
-
return
|
|
606
|
+
return PARSE_FAILURE_PATTERN.test(reason);
|
|
549
607
|
}
|
|
550
608
|
function contentToText(content) {
|
|
551
609
|
if (typeof content === "string") {
|
|
@@ -627,6 +685,14 @@ function createWebLLMBridge(engine) {
|
|
|
627
685
|
init_parse_action();
|
|
628
686
|
var DEFAULT_PLANNER = { kind: "heuristic" };
|
|
629
687
|
var MAX_CONSECUTIVE_ERRORS = 2;
|
|
688
|
+
var LOOP_WINDOW = 8;
|
|
689
|
+
var LOOP_THRESHOLD = 3;
|
|
690
|
+
function actionSignature(action) {
|
|
691
|
+
if (action.type === "click" || action.type === "type" || action.type === "focus") {
|
|
692
|
+
return `${action.type}:${action.selector}`;
|
|
693
|
+
}
|
|
694
|
+
return null;
|
|
695
|
+
}
|
|
630
696
|
var BrowserAgent = class {
|
|
631
697
|
session;
|
|
632
698
|
maxSteps;
|
|
@@ -634,6 +700,7 @@ var BrowserAgent = class {
|
|
|
634
700
|
events;
|
|
635
701
|
isStopped = false;
|
|
636
702
|
signal;
|
|
703
|
+
recentActionSigs = [];
|
|
637
704
|
constructor(config, events = {}) {
|
|
638
705
|
this.session = {
|
|
639
706
|
id: crypto.randomUUID(),
|
|
@@ -660,6 +727,7 @@ var BrowserAgent = class {
|
|
|
660
727
|
}
|
|
661
728
|
async start() {
|
|
662
729
|
this.isStopped = false;
|
|
730
|
+
this.recentActionSigs = [];
|
|
663
731
|
this.session.isRunning = true;
|
|
664
732
|
this.events.onStart?.(this.getSession());
|
|
665
733
|
return this.runLoop();
|
|
@@ -764,15 +832,31 @@ var BrowserAgent = class {
|
|
|
764
832
|
if (plannerResult.memory !== void 0) {
|
|
765
833
|
this.session.memory = plannerResult.memory;
|
|
766
834
|
}
|
|
767
|
-
return this.processAction(plannerResult);
|
|
835
|
+
return this.processAction(plannerResult, snapshot.candidates);
|
|
768
836
|
} catch (error) {
|
|
769
837
|
return { status: "error", message: String(error) };
|
|
770
838
|
}
|
|
771
839
|
}
|
|
772
|
-
async processAction(plannerResult) {
|
|
840
|
+
async processAction(plannerResult, candidates) {
|
|
773
841
|
const { action } = plannerResult;
|
|
774
842
|
const reflection = plannerResult.evaluation !== void 0 || plannerResult.memory !== void 0 || plannerResult.nextGoal !== void 0 ? { evaluation: plannerResult.evaluation, memory: plannerResult.memory, nextGoal: plannerResult.nextGoal } : void 0;
|
|
775
|
-
const
|
|
843
|
+
const sig = actionSignature(action);
|
|
844
|
+
if (sig) {
|
|
845
|
+
this.recentActionSigs.push(sig);
|
|
846
|
+
if (this.recentActionSigs.length > LOOP_WINDOW) {
|
|
847
|
+
this.recentActionSigs.shift();
|
|
848
|
+
}
|
|
849
|
+
const repeatCount = this.recentActionSigs.filter((s) => s === sig).length;
|
|
850
|
+
if (repeatCount >= LOOP_THRESHOLD) {
|
|
851
|
+
return {
|
|
852
|
+
status: "done",
|
|
853
|
+
action,
|
|
854
|
+
message: "Loop detected \u2014 goal appears to be complete.",
|
|
855
|
+
reflection
|
|
856
|
+
};
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
const risk = assessRisk(action, candidates);
|
|
776
860
|
if (risk === "blocked") {
|
|
777
861
|
return { status: "blocked", action, message: `Blocked action: ${JSON.stringify(action)}`, reflection };
|
|
778
862
|
}
|
package/dist/lib.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/shared/parse-action.ts", "../src/core/executor.ts", "../src/core/observer.ts", "../src/core/planner.ts", "../src/shared/safety.ts", "../src/core/webllm-bridge.ts", "../src/core/prompt.ts", "../src/lib/index.ts"],
|
|
4
|
-
"sourcesContent": ["import type { AgentAction, PlannerResult } from \"./contracts\";\n\nconst VALID_TYPES = new Set([\n \"click\", \"type\", \"navigate\", \"extract\", \"scroll\", \"focus\", \"wait\", \"done\",\n]);\n\n/**\n * Extract the first complete JSON object from text using bracket counting.\n * More robust than regex: handles prose before/after JSON, and repairs\n * truncated output (e.g. when the model hits a token limit mid-JSON).\n */\nfunction extractFirstJsonObject(text: string): string | null {\n const start = text.indexOf(\"{\");\n if (start === -1) return null;\n\n let depth = 0;\n let inString = false;\n let escaped = false;\n\n for (let i = start; i < text.length; i++) {\n const ch = text[i];\n if (escaped) { escaped = false; continue; }\n if (ch === \"\\\\\" && inString) { escaped = true; continue; }\n if (ch === '\"') { inString = !inString; continue; }\n if (inString) continue;\n if (ch === \"{\") depth++;\n else if (ch === \"}\") {\n depth--;\n if (depth === 0) return text.slice(start, i + 1);\n }\n }\n\n // Truncated JSON (hit token limit mid-output) \u2014 close remaining open braces.\n if (depth > 0) {\n return text.slice(start) + \"}\".repeat(depth);\n }\n\n return null;\n}\n\n/**\n * Parse an AgentAction from raw LLM output.\n *\n * Handles bare JSON, markdown fences, and JSON embedded in prose.\n * Returns a \"done\" action if parsing fails, so the caller always gets a valid AgentAction.\n */\nexport function parseAction(raw: string): AgentAction {\n const fenceMatch = raw.match(/```(?:json)?\\s*([\\s\\S]*?)```/);\n const candidate = fenceMatch ? fenceMatch[1].trim() : raw.trim();\n\n const jsonStr = extractFirstJsonObject(candidate);\n if (!jsonStr) {\n return { type: \"done\", reason: `No JSON object found in: ${raw.slice(0, 120)}` };\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(jsonStr);\n } catch {\n return { type: \"done\", reason: `JSON parse error for: ${jsonStr.slice(0, 120)}` };\n }\n\n if (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n return { type: \"done\", reason: \"Parsed value is not an object\" };\n }\n\n const obj = parsed as Record<string, unknown>;\n if (typeof obj.type !== \"string\" || !VALID_TYPES.has(obj.type)) {\n return { type: \"done\", reason: `Unknown or missing action type: ${String(obj.type)}` };\n }\n\n return obj as unknown as AgentAction;\n}\n\n/**\n * Parse a full PlannerResult from raw LLM output.\n *\n * Accepts the reflection+action format:\n * { \"evaluation\": \"...\", \"memory\": \"...\", \"nextGoal\": \"...\", \"action\": { ... } }\n * Also supports legacy `next_goal` key for backward compatibility.\n *\n * Also accepts a bare AgentAction for backward compatibility with simple bridges.\n */\nexport function parsePlannerResult(raw: string): PlannerResult {\n const fenceMatch = raw.match(/```(?:json)?\\s*([\\s\\S]*?)```/);\n const candidate = fenceMatch ? fenceMatch[1].trim() : raw.trim();\n\n const jsonStr = extractFirstJsonObject(candidate);\n if (!jsonStr) {\n return { action: { type: \"done\", reason: `No JSON found in: ${raw.slice(0, 120)}` } };\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(jsonStr);\n } catch {\n return { action: { type: \"done\", reason: `JSON parse error: ${jsonStr.slice(0, 120)}` } };\n }\n\n if (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n return { action: { type: \"done\", reason: \"Parsed value is not an object\" } };\n }\n\n const obj = parsed as Record<string, unknown>;\n\n // Full reflection format: { evaluation, memory, nextGoal, action }\n if (typeof obj.action === \"object\" && obj.action !== null) {\n const action = parseAction(JSON.stringify(obj.action));\n return {\n action,\n evaluation: typeof obj.evaluation === \"string\" ? obj.evaluation : undefined,\n memory: typeof obj.memory === \"string\" ? obj.memory : undefined,\n nextGoal:\n typeof obj.nextGoal === \"string\"\n ? obj.nextGoal\n : typeof obj.next_goal === \"string\"\n ? obj.next_goal\n : undefined,\n };\n }\n\n // Fallback: bare AgentAction (no reflection fields)\n return { action: parseAction(jsonStr) };\n}\n", "import type { AgentAction } from \"../shared/contracts\";\n\nfunction mustFind(selector: string): HTMLElement {\n const node = document.querySelector(selector);\n if (node instanceof HTMLElement) {\n return node;\n }\n\n // Fallback: if selector looks like a bare nth-of-type or is invalid,\n // try to find the element by tag and common attributes extracted from the selector\n const tagMatch = selector.match(/^(\\w+)/);\n if (tagMatch) {\n const tag = tagMatch[1];\n // Try matching by name, placeholder, or aria-label attributes in the selector\n const attrMatch = selector.match(/\\[(\\w[\\w-]*)=[\"']?([^\\]\"']+)[\"']?\\]/);\n if (attrMatch) {\n const fallback = document.querySelector(`${tag}[${attrMatch[1]}=\"${attrMatch[2]}\"]`);\n if (fallback instanceof HTMLElement) return fallback;\n }\n // Last resort: if only one element of that tag exists, use it\n const allOfTag = document.querySelectorAll(tag);\n if (allOfTag.length === 1 && allOfTag[0] instanceof HTMLElement) {\n return allOfTag[0];\n }\n }\n\n throw new Error(`Selector not found: ${selector}`);\n}\n\nfunction dispatchInputEvents(el: HTMLInputElement | HTMLTextAreaElement): void {\n el.dispatchEvent(new InputEvent(\"input\", { bubbles: true, cancelable: true }));\n el.dispatchEvent(new Event(\"change\", { bubbles: true }));\n}\n\nexport async function executeAction(action: AgentAction): Promise<string> {\n switch (action.type) {\n case \"click\": {\n const el = mustFind(action.selector);\n if ((el as HTMLButtonElement).disabled) {\n throw new Error(`Element is disabled: ${action.selector}`);\n }\n el.click();\n return `Clicked ${action.selector}`;\n }\n case \"type\": {\n const input = mustFind(action.selector) as HTMLInputElement | HTMLTextAreaElement;\n input.focus();\n if (action.clearFirst) {\n input.value = \"\";\n dispatchInputEvents(input);\n }\n input.value = `${input.value}${action.text}`;\n dispatchInputEvents(input);\n if (input.value.indexOf(action.text) === -1) {\n throw new Error(`Type verification failed: value did not update for ${action.selector}`);\n }\n return `Typed into ${action.selector}`;\n }\n case \"navigate\": {\n window.location.href = action.url;\n return `Navigated to ${action.url}`;\n }\n case \"extract\": {\n const value = mustFind(action.selector).innerText.trim();\n if (!value) {\n throw new Error(`Extract returned empty text from ${action.selector}`);\n }\n return `${action.label}: ${value}`;\n }\n case \"scroll\": {\n const target = action.selector ? mustFind(action.selector) : document.documentElement;\n target.scrollBy({ top: action.deltaY, behavior: \"smooth\" });\n return `Scrolled ${action.deltaY > 0 ? \"down\" : \"up\"} ${Math.abs(action.deltaY)}px`;\n }\n case \"focus\": {\n mustFind(action.selector).focus();\n return `Focused ${action.selector}`;\n }\n case \"wait\": {\n await new Promise((resolve) => setTimeout(resolve, action.ms));\n return `Waited ${action.ms}ms`;\n }\n case \"done\": {\n return action.reason;\n }\n default:\n return \"No-op\";\n }\n}\n", "import type { CandidateElement, PageSnapshot } from \"../shared/contracts\";\n\nconst CANDIDATE_SELECTOR =\n \"a,button,input,textarea,select,[role='button'],[role='link'],[contenteditable='true']\";\n\nconst MAX_CANDIDATES = 60;\n\nfunction cssPath(element: Element): string {\n if (!(element instanceof HTMLElement)) {\n return element.tagName.toLowerCase();\n }\n\n if (element.id) {\n return `#${CSS.escape(element.id)}`;\n }\n\n // For form elements, prefer attribute-based selectors that are more stable\n const tag = element.tagName.toLowerCase();\n if (tag === \"input\" || tag === \"textarea\" || tag === \"select\") {\n const name = element.getAttribute(\"name\");\n if (name && document.querySelectorAll(`${tag}[name=${CSS.escape(name)}]`).length === 1) {\n return `${tag}[name=${CSS.escape(name)}]`;\n }\n const type = (element as HTMLInputElement).type;\n const placeholder = element.getAttribute(\"placeholder\");\n if (placeholder && document.querySelectorAll(`${tag}[placeholder=${CSS.escape(placeholder)}]`).length === 1) {\n return `${tag}[placeholder=${CSS.escape(placeholder)}]`;\n }\n const ariaLabel = element.getAttribute(\"aria-label\");\n if (ariaLabel && document.querySelectorAll(`${tag}[aria-label=${CSS.escape(ariaLabel)}]`).length === 1) {\n return `${tag}[aria-label=${CSS.escape(ariaLabel)}]`;\n }\n // Combine name + type for uniqueness\n if (name && type) {\n const combo = `${tag}[name=${CSS.escape(name)}][type=${CSS.escape(type)}]`;\n if (document.querySelectorAll(combo).length === 1) {\n return combo;\n }\n }\n }\n\n // For buttons/links, prefer text-based or aria selectors\n if (tag === \"button\" || tag === \"a\") {\n const ariaLabel = element.getAttribute(\"aria-label\");\n if (ariaLabel && document.querySelectorAll(`${tag}[aria-label=${CSS.escape(ariaLabel)}]`).length === 1) {\n return `${tag}[aria-label=${CSS.escape(ariaLabel)}]`;\n }\n }\n\n const parts: string[] = [];\n let current: HTMLElement | null = element;\n while (current && parts.length < 4) {\n let part = current.tagName.toLowerCase();\n if (current.classList.length > 0) {\n part += `.${Array.from(current.classList).slice(0, 2).map(CSS.escape).join(\".\")}`;\n }\n const parent: HTMLElement | null = current.parentElement;\n if (parent) {\n const siblings = Array.from(parent.children).filter((s: Element) => s.tagName === current!.tagName);\n if (siblings.length > 1) {\n const index = siblings.indexOf(current) + 1;\n part += `:nth-of-type(${index})`;\n }\n }\n parts.unshift(part);\n current = parent;\n }\n return parts.join(\" > \");\n}\n\nfunction isVisible(el: HTMLElement): boolean {\n if (el.offsetParent === null && el.tagName !== \"BODY\") return false;\n const style = window.getComputedStyle(el);\n if (style.display === \"none\" || style.visibility === \"hidden\" || style.opacity === \"0\") return false;\n // Zero-dimension elements are functionally hidden\n const rect = el.getBoundingClientRect();\n return rect.width > 0 || rect.height > 0;\n}\n\nfunction isInViewport(el: HTMLElement): boolean {\n const rect = el.getBoundingClientRect();\n return (\n rect.bottom > 0 &&\n rect.top < window.innerHeight &&\n rect.right > 0 &&\n rect.left < window.innerWidth\n );\n}\n\n/** Resolve the visible label text via for/id, aria-labelledby, aria-label, or wrapping <label>. */\nfunction getAssociatedLabel(el: HTMLElement): string {\n if (el.id) {\n const label = document.querySelector<HTMLLabelElement>(`label[for=\"${CSS.escape(el.id)}\"]`);\n if (label) return label.innerText.trim();\n }\n\n const labelledBy = el.getAttribute(\"aria-labelledby\");\n if (labelledBy) {\n const labelEl = document.getElementById(labelledBy);\n if (labelEl) return labelEl.innerText.trim();\n }\n\n const ariaLabel = el.getAttribute(\"aria-label\");\n if (ariaLabel) return ariaLabel.trim();\n\n const parentLabel = el.closest(\"label\");\n if (parentLabel) {\n return Array.from(parentLabel.childNodes)\n .filter((n) => n.nodeType === Node.TEXT_NODE)\n .map((n) => n.textContent?.trim() ?? \"\")\n .filter(Boolean)\n .join(\" \");\n }\n\n return \"\";\n}\n\nexport function collectSnapshot(): PageSnapshot {\n const allNodes = Array.from(\n document.querySelectorAll<HTMLElement>(CANDIDATE_SELECTOR)\n ).filter(isVisible);\n\n // In-viewport elements first so the model sees the most relevant candidates first\n const inView = allNodes.filter(isInViewport);\n const offScreen = allNodes.filter((el) => !isInViewport(el));\n const nodes = [...inView, ...offScreen].slice(0, MAX_CANDIDATES);\n\n const candidates: CandidateElement[] = nodes.map((node) => {\n const placeholder =\n (node as HTMLInputElement).placeholder?.trim() || node.getAttribute(\"placeholder\")?.trim();\n const associatedLabel = getAssociatedLabel(node);\n return {\n selector: cssPath(node),\n role: node.getAttribute(\"role\") ?? node.tagName.toLowerCase(),\n text: (node.innerText || node.getAttribute(\"name\") || \"\").trim().slice(0, 120),\n placeholder: placeholder || undefined,\n label: associatedLabel || undefined,\n };\n });\n\n const textPreview = document.body.innerText.replace(/\\s+/g, \" \").trim().slice(0, 1500);\n\n return {\n url: window.location.href,\n title: document.title,\n textPreview,\n candidates,\n };\n}\n", "import type { AgentAction, CandidateElement, PlannerConfig, PlannerInput, PlannerResult } from \"../shared/contracts\";\n\ntype WebLLMBridge = {\n // Bridge may return PlannerResult (new), AgentAction (legacy), or raw LLM text.\n plan(input: PlannerInput, modelId?: string): Promise<PlannerResult | AgentAction | string>;\n // Optional retry hook that keeps chat history and asks for corrected JSON.\n retryInvalidJson?(input: PlannerInput, badOutput: string, modelId?: string): Promise<PlannerResult | AgentAction | string>;\n};\n\nconst URL_PATTERN = /(?:go to|navigate to|open)\\s+(https?:\\/\\/\\S+)/i;\nconst SEARCH_PATTERN = /search(?:\\s+for)?\\s+(.+)/i;\nconst FILL_PATTERN = /(?:fill|type|enter)\\s+\"?([^\"]+)\"?\\s+(?:in(?:to)?|for|on)\\s+(.+)/i;\nconst CLICK_PATTERN = /click(?:\\s+(?:on|the))?\\s+(.+)/i;\n\nfunction findByText(candidates: CandidateElement[], text: string): CandidateElement | undefined {\n const lower = text.toLowerCase();\n return candidates.find(\n (c) =>\n c.text.toLowerCase().includes(lower) ||\n (c.placeholder?.toLowerCase().includes(lower) ?? false) ||\n (c.label?.toLowerCase().includes(lower) ?? false)\n );\n}\n\nfunction findInput(candidates: CandidateElement[]): CandidateElement | undefined {\n return candidates.find(\n (c) => c.role === \"input\" || c.role === \"textarea\" || c.selector.includes(\"input\") || c.selector.includes(\"textarea\")\n );\n}\n\nfunction findButton(candidates: CandidateElement[]): CandidateElement | undefined {\n return candidates.find(\n (c) => c.role === \"button\" || c.role === \"a\" || c.selector.includes(\"button\") || c.selector.includes(\"a\")\n );\n}\n\nfunction heuristicPlan(input: PlannerInput): AgentAction {\n const { goal, snapshot, history } = input;\n\n const navMatch = goal.match(URL_PATTERN);\n if (navMatch) {\n return { type: \"navigate\", url: navMatch[1] };\n }\n\n const fillMatch = goal.match(FILL_PATTERN);\n if (fillMatch) {\n const [, text, fieldHint] = fillMatch;\n const target = findByText(snapshot.candidates, fieldHint) ?? findInput(snapshot.candidates);\n if (target) {\n return { type: \"type\", selector: target.selector, text, clearFirst: true, label: target.label || target.text || target.placeholder };\n }\n }\n\n const searchMatch = goal.match(SEARCH_PATTERN);\n if (searchMatch) {\n const input = findInput(snapshot.candidates);\n if (input) {\n return { type: \"type\", selector: input.selector, text: searchMatch[1].trim(), clearFirst: true, label: input.label || input.text || input.placeholder };\n }\n }\n\n const clickMatch = goal.match(CLICK_PATTERN);\n if (clickMatch) {\n const target = findByText(snapshot.candidates, clickMatch[1].trim());\n if (target) {\n return { type: \"click\", selector: target.selector, label: target.text };\n }\n }\n\n const firstInput = findInput(snapshot.candidates);\n const firstButton = findButton(snapshot.candidates);\n\n if (firstInput && !history.some((h) => h.startsWith(\"Typed\"))) {\n const searchTerm = goal.replace(/.*(?:search|find|look up)\\s+/i, \"\").trim();\n return { type: \"type\", selector: firstInput.selector, text: searchTerm, clearFirst: true, label: firstInput.label || firstInput.text || firstInput.placeholder };\n }\n\n if (firstButton && !history.some((h) => h.startsWith(\"Clicked\"))) {\n return { type: \"click\", selector: firstButton.selector, label: firstButton.text };\n }\n\n return { type: \"done\", reason: \"No further heuristic actions available\" };\n}\n\n/** Normalize whatever a bridge returns into a PlannerResult. */\nfunction toPlannerResult(raw: PlannerResult | AgentAction): PlannerResult {\n // New format: has an `action` key that is an object\n if (\"action\" in raw && typeof (raw as PlannerResult).action === \"object\") {\n return raw as PlannerResult;\n }\n // Legacy format: bare AgentAction\n return { action: raw as AgentAction };\n}\n\nasync function parsePlannerText(raw: string): Promise<PlannerResult> {\n const parser = await import(\"../shared/parse-action\");\n return parser.parsePlannerResult(raw);\n}\n\nasync function normalizeBridgeResponse(\n raw: PlannerResult | AgentAction | string\n): Promise<{ result: PlannerResult; parseFailed: boolean; rawText?: string }> {\n if (typeof raw === \"string\") {\n const parsed = await parsePlannerText(raw);\n const parseFailed = parsed.action.type === \"done\" &&\n /(No JSON|JSON parse error|Parsed value is not an object|Unknown or missing action type)/.test(parsed.action.reason);\n return { result: parsed, parseFailed, rawText: raw };\n }\n\n return { result: toPlannerResult(raw), parseFailed: false };\n}\n\nexport async function planNextAction(config: PlannerConfig, input: PlannerInput): Promise<PlannerResult> {\n if (config.kind === \"heuristic\") {\n return { action: heuristicPlan(input) };\n }\n\n const bridge = (window as Window & { __browserAgentWebLLM?: WebLLMBridge }).__browserAgentWebLLM;\n if (!bridge) {\n return {\n action: {\n type: \"done\",\n reason: \"WebLLM bridge is not configured. Use heuristic mode or wire a WebLLM bridge implementation.\"\n }\n };\n }\n\n const plannerInput = { ...input, systemPrompt: config.systemPrompt };\n const firstAttempt = await normalizeBridgeResponse(await bridge.plan(plannerInput, config.modelId));\n\n if (!firstAttempt.parseFailed) {\n return firstAttempt.result;\n }\n\n if (bridge.retryInvalidJson && firstAttempt.rawText) {\n const retryAttempt = await normalizeBridgeResponse(\n await bridge.retryInvalidJson(plannerInput, firstAttempt.rawText, config.modelId)\n );\n\n if (!retryAttempt.parseFailed) {\n return retryAttempt.result;\n }\n }\n\n return {\n action: {\n type: \"done\",\n reason: \"WebLLM output could not be parsed after retry.\"\n }\n };\n}\n", "import type { AgentAction, RiskLevel } from \"./contracts\";\n\nconst RISKY_KEYWORDS = /\\b(delete|remove|pay|purchase|submit|confirm|checkout|transfer|withdraw|send)\\b/i;\n\nfunction elementTextRisky(text?: string): boolean {\n return text != null && RISKY_KEYWORDS.test(text);\n}\n\nexport function assessRisk(action: AgentAction): RiskLevel {\n switch (action.type) {\n case \"navigate\": {\n try {\n const next = new URL(action.url);\n if (![\"http:\", \"https:\"].includes(next.protocol)) {\n return \"blocked\";\n }\n } catch {\n return \"blocked\";\n }\n return \"safe\";\n }\n case \"click\":\n return elementTextRisky(action.label) ? \"review\" : \"safe\";\n case \"type\":\n return elementTextRisky(action.label) ? \"review\" : \"safe\";\n case \"focus\":\n case \"scroll\":\n case \"wait\":\n return \"safe\";\n case \"extract\":\n return \"review\";\n case \"done\":\n return \"safe\";\n default:\n return \"review\";\n }\n}\n", "import type { PlannerInput, PlannerResult } from \"../shared/contracts\";\nimport { parsePlannerResult } from \"../shared/parse-action\";\nimport { buildSystemPrompt, buildUserMessage } from \"./prompt\";\n\nexport const INVALID_JSON_RETRY_MESSAGE = [\n \"Your reply was not valid JSON. Output ONLY a JSON object \u2014 no explanation, no markdown, no extra text.\",\n 'Required format: {\"evaluation\":\"...\",\"memory\":\"...\",\"nextGoal\":\"...\",\"action\":{\"type\":\"click\",\"selector\":\"EXACT_SELECTOR\",\"label\":\"...\"}}',\n].join(\"\\n\");\n\nconst BARE_ACTION_RETRY_MESSAGE = [\n \"Still not valid JSON. Output ONLY the action object. No evaluation, memory, or nextGoal fields.\",\n 'Example: {\"type\":\"type\",\"selector\":\"EXACT_SELECTOR_FROM_LIST\",\"text\":\"value\",\"clearFirst\":true}',\n 'Example: {\"type\":\"click\",\"selector\":\"EXACT_SELECTOR_FROM_LIST\",\"label\":\"button text\"}',\n].join(\"\\n\");\n\ntype ChatRole = \"system\" | \"user\" | \"assistant\";\n\ntype ChatMessage = {\n role: ChatRole;\n content: string;\n};\n\ntype CompletionRequest = {\n messages: ChatMessage[];\n temperature?: number;\n max_tokens?: number;\n model?: string;\n};\n\ntype CompletionResponse = {\n choices?: Array<{\n message?: {\n content?: unknown;\n };\n }>;\n};\n\nexport type WebLLMEngineLike = {\n chat: {\n completions: {\n create(request: CompletionRequest): Promise<CompletionResponse>;\n };\n };\n};\n\nexport type BrowserAgentWebLLMBridge = {\n plan(input: PlannerInput, modelId?: string): Promise<PlannerResult>;\n retryInvalidJson(input: PlannerInput, badOutput: string, modelId?: string): Promise<PlannerResult>;\n};\n\nfunction isParseFailure(result: PlannerResult): boolean {\n if (result.action.type !== \"done\") {\n return false;\n }\n\n const reason = result.action.reason;\n return /(No JSON|JSON parse error|Parsed value is not an object|Unknown or missing action type)/.test(reason);\n}\n\nfunction contentToText(content: unknown): string {\n if (typeof content === \"string\") {\n return content;\n }\n\n if (Array.isArray(content)) {\n const chunks = content\n .map((part) => {\n if (typeof part === \"string\") {\n return part;\n }\n if (typeof part === \"object\" && part !== null && \"text\" in part && typeof part.text === \"string\") {\n return part.text;\n }\n return \"\";\n })\n .filter(Boolean);\n\n return chunks.join(\"\\n\");\n }\n\n return \"\";\n}\n\nfunction failureResult(attempts: number): PlannerResult {\n return {\n action: {\n type: \"done\",\n reason: `WebLLM returned invalid JSON after ${attempts} attempt${attempts === 1 ? \"\" : \"s\"}. Unable to continue.`\n }\n };\n}\n\nasync function createCompletion(engine: WebLLMEngineLike, messages: ChatMessage[], modelId?: string): Promise<string> {\n const response = await engine.chat.completions.create({\n messages,\n temperature: 0,\n max_tokens: 700,\n ...(modelId ? { model: modelId } : {})\n });\n\n return contentToText(response.choices?.[0]?.message?.content).trim();\n}\n\nfunction buildBaseMessages(input: PlannerInput): ChatMessage[] {\n return [\n { role: \"system\", content: buildSystemPrompt(input.systemPrompt) },\n { role: \"user\", content: buildUserMessage(input) }\n ];\n}\n\nasync function retryInvalidJsonWithHistory(\n engine: WebLLMEngineLike,\n baseMessages: ChatMessage[],\n badOutput: string,\n modelId?: string\n): Promise<PlannerResult> {\n // Attempt 2: improved message with format example\n const attempt2Messages: ChatMessage[] = [\n ...baseMessages,\n { role: \"assistant\", content: badOutput },\n { role: \"user\", content: INVALID_JSON_RETRY_MESSAGE }\n ];\n\n const raw2 = await createCompletion(engine, attempt2Messages, modelId);\n const result2 = parsePlannerResult(raw2);\n if (!isParseFailure(result2)) return result2;\n\n // Attempt 3: ask for bare action only (simpler target for small models)\n const attempt3Messages: ChatMessage[] = [\n ...attempt2Messages,\n { role: \"assistant\", content: raw2 },\n { role: \"user\", content: BARE_ACTION_RETRY_MESSAGE }\n ];\n\n const raw3 = await createCompletion(engine, attempt3Messages, modelId);\n const result3 = parsePlannerResult(raw3);\n if (!isParseFailure(result3)) return result3;\n\n return failureResult(3);\n}\n\nexport function createWebLLMBridge(engine: WebLLMEngineLike): BrowserAgentWebLLMBridge {\n return {\n async plan(input: PlannerInput, modelId?: string): Promise<PlannerResult> {\n const baseMessages = buildBaseMessages(input);\n\n // Attempt 1: normal\n const raw1 = await createCompletion(engine, baseMessages, modelId);\n const result1 = parsePlannerResult(raw1);\n if (!isParseFailure(result1)) return result1;\n\n // Attempts 2 & 3 with progressively simpler asks\n return retryInvalidJsonWithHistory(engine, baseMessages, raw1, modelId);\n },\n\n async retryInvalidJson(input: PlannerInput, badOutput: string, modelId?: string): Promise<PlannerResult> {\n const baseMessages = buildBaseMessages(input);\n return retryInvalidJsonWithHistory(engine, baseMessages, badOutput, modelId);\n }\n };\n}\n", "import type { CandidateElement, PlannerInput } from \"../shared/contracts\";\n\nconst MAX_TEXT_PREVIEW_LENGTH = 800;\n\nconst DEFAULT_SYSTEM_PROMPT = [\n \"You are OmniBrowser Agent, an on-page web automation planner.\",\n \"Choose exactly one next action using the provided page snapshot.\",\n \"\",\n \"Output rules:\",\n '- Reply with only one valid JSON object (no markdown fences, no prose).',\n '- JSON shape must be: { \"evaluation\": string, \"memory\": string, \"nextGoal\": string, \"action\": AgentAction }.',\n '- Keep evaluation/memory/nextGoal concise but informative.',\n \"\",\n \"Valid AgentAction shapes:\",\n '- {\"type\":\"click\",\"selector\":\"<css>\",\"label\":\"<optional>\"}',\n '- {\"type\":\"type\",\"selector\":\"<css>\",\"text\":\"<text>\",\"clearFirst\":true|false,\"label\":\"<optional>\"}',\n '- {\"type\":\"navigate\",\"url\":\"https://...\"}',\n '- {\"type\":\"extract\",\"selector\":\"<css>\",\"label\":\"<label>\"}',\n '- {\"type\":\"scroll\",\"selector\":\"<optional css>\",\"deltaY\":number}',\n '- {\"type\":\"focus\",\"selector\":\"<css>\"}',\n '- {\"type\":\"wait\",\"ms\":number}',\n '- {\"type\":\"done\",\"reason\":\"<reason>\"}',\n \"\",\n \"IMPORTANT: You MUST use selectors exactly as listed in the candidates. NEVER invent or guess selectors.\",\n \"If you cannot find a matching candidate for a target element, use the closest match from the candidates list.\",\n \"When previous step failed, recover by trying a different candidate selector or fallback strategy.\"\n].join(\"\\n\");\n\nfunction formatCandidate(candidate: CandidateElement, index: number): string {\n const parts = [\n `${candidate.role || \"element\"}`,\n `selector: ${JSON.stringify(candidate.selector)}`,\n `text: ${JSON.stringify(candidate.text || \"\")}`\n ];\n\n if (candidate.label) {\n parts.push(`label: ${JSON.stringify(candidate.label)}`);\n }\n if (candidate.placeholder) {\n parts.push(`placeholder: ${JSON.stringify(candidate.placeholder)}`);\n }\n\n return `[${index + 1}] ${parts.join(\" | \")}`;\n}\n\nexport function buildSystemPrompt(customPrompt?: string): string {\n if (!customPrompt?.trim()) {\n return DEFAULT_SYSTEM_PROMPT;\n }\n\n return `${DEFAULT_SYSTEM_PROMPT}\\n\\nAdditional instructions:\\n${customPrompt.trim()}`;\n}\n\nexport function buildUserMessage(input: PlannerInput): string {\n const { goal, snapshot, history, memory, lastError } = input;\n const candidates = snapshot.candidates.map(formatCandidate).join(\"\\n\");\n const historyLines = history.length > 0\n ? history.map((step, index) => `${index + 1}. ${step}`).join(\"\\n\")\n : \"(none)\";\n\n return [\n `Goal: ${goal}`,\n \"\",\n \"Page snapshot:\",\n `- URL: ${snapshot.url}`,\n `- Title: ${snapshot.title}`,\n `- Text preview (first ${MAX_TEXT_PREVIEW_LENGTH} chars): ${JSON.stringify(snapshot.textPreview.slice(0, MAX_TEXT_PREVIEW_LENGTH))}`,\n \"\",\n `Interactive candidates (${snapshot.candidates.length}):`,\n candidates || \"(none)\",\n \"\",\n \"History:\",\n historyLines,\n \"\",\n `Working memory: ${memory ? JSON.stringify(memory) : \"(none)\"}`,\n `Last error: ${lastError ? JSON.stringify(lastError) : \"(none)\"}`,\n \"If Last error is present, recover and choose a different valid action.\"\n ].join(\"\\n\");\n}\n", "import { executeAction } from \"../core/executor\";\nimport { collectSnapshot } from \"../core/observer\";\nimport { planNextAction } from \"../core/planner\";\nimport type {\n AgentSession,\n ContentResult,\n LibraryAgentConfig,\n LibraryAgentEvents,\n PlannerConfig,\n PlannerResult\n} from \"../shared/contracts\";\nimport { assessRisk } from \"../shared/safety\";\n\nconst DEFAULT_PLANNER: PlannerConfig = { kind: \"heuristic\" };\n\n/** Max consecutive errors before the agent gives up instead of retrying */\nconst MAX_CONSECUTIVE_ERRORS = 2;\n\nexport class BrowserAgent {\n private session: AgentSession;\n private maxSteps: number;\n private stepDelayMs: number;\n private events: LibraryAgentEvents;\n private isStopped = false;\n private signal?: AbortSignal;\n\n constructor(config: LibraryAgentConfig, events: LibraryAgentEvents = {}) {\n this.session = {\n id: crypto.randomUUID(),\n tabId: null,\n goal: config.goal,\n mode: config.mode ?? \"human-approved\",\n planner: config.planner ?? DEFAULT_PLANNER,\n history: [],\n isRunning: false\n };\n\n this.maxSteps = config.maxSteps ?? 20;\n this.stepDelayMs = config.stepDelayMs ?? 500;\n this.events = events;\n this.signal = config.signal;\n }\n\n getSession(): AgentSession {\n return { ...this.session, history: [...this.session.history] };\n }\n\n get isRunning(): boolean {\n return this.session.isRunning;\n }\n\n get hasPendingAction(): boolean {\n return this.session.pendingAction != null;\n }\n\n async start(): Promise<ContentResult> {\n this.isStopped = false;\n this.session.isRunning = true;\n this.events.onStart?.(this.getSession());\n return this.runLoop();\n }\n\n async resume(): Promise<ContentResult> {\n if (this.session.pendingAction) {\n const approvalResult = await this.approvePendingAction();\n if (approvalResult.status === \"error\") {\n return approvalResult;\n }\n }\n this.session.isRunning = true;\n return this.runLoop();\n }\n\n private async runLoop(): Promise<ContentResult> {\n let consecutiveErrors = 0;\n let lastError: string | undefined;\n\n for (let step = 0; step < this.maxSteps; step += 1) {\n if (this.isStopped || !this.session.isRunning) {\n return { status: \"done\", message: \"Stopped\" };\n }\n\n if (this.signal?.aborted) {\n this.session.isRunning = false;\n return { status: \"done\", message: \"Aborted\" };\n }\n\n const result = await this.tick(lastError);\n this.events.onStep?.(result, this.getSession());\n\n if (result.status === \"error\") {\n consecutiveErrors += 1;\n lastError = result.message;\n this.session.history.push(`Error: ${result.message}`);\n\n if (consecutiveErrors >= MAX_CONSECUTIVE_ERRORS) {\n this.session.isRunning = false;\n this.events.onError?.(new Error(result.message), this.getSession());\n this.events.onDone?.(result, this.getSession());\n return result;\n }\n\n await this.delay(this.stepDelayMs);\n continue;\n }\n\n consecutiveErrors = 0;\n lastError = undefined;\n this.session.history.push(result.message);\n\n if (result.status === \"needs_approval\") {\n this.session.pendingAction = result.action;\n this.session.isRunning = false;\n if (result.action) {\n this.events.onApprovalRequired?.(result.action, this.getSession());\n }\n return result;\n }\n\n if ([\"done\", \"blocked\"].includes(result.status)) {\n this.session.isRunning = false;\n this.events.onDone?.(result, this.getSession());\n return result;\n }\n\n await this.delay(this.stepDelayMs);\n }\n\n const result: ContentResult = { status: \"done\", message: \"Reached max steps\" };\n this.session.history.push(result.message);\n this.session.isRunning = false;\n this.events.onMaxStepsReached?.(this.getSession());\n this.events.onDone?.(result, this.getSession());\n return result;\n }\n\n async approvePendingAction(): Promise<ContentResult> {\n if (!this.session.pendingAction) {\n return { status: \"error\", message: \"No pending action to approve\" };\n }\n\n try {\n const message = await executeAction(this.session.pendingAction);\n const result: ContentResult = {\n status: \"executed\",\n message,\n action: this.session.pendingAction\n };\n this.session.history.push(message);\n this.session.pendingAction = undefined;\n this.session.isRunning = true;\n this.events.onStep?.(result, this.getSession());\n return result;\n } catch (error) {\n this.session.isRunning = false;\n this.events.onError?.(error, this.getSession());\n return { status: \"error\", message: String(error) };\n }\n }\n\n stop(): void {\n this.isStopped = true;\n this.session.isRunning = false;\n }\n\n private async tick(lastError?: string): Promise<ContentResult> {\n try {\n const snapshot = collectSnapshot();\n const plannerResult = await planNextAction(this.session.planner, {\n goal: this.session.goal,\n snapshot,\n history: this.session.history,\n lastError,\n memory: this.session.memory\n });\n\n // Carry working memory forward across steps\n if (plannerResult.memory !== undefined) {\n this.session.memory = plannerResult.memory;\n }\n\n return this.processAction(plannerResult);\n } catch (error) {\n return { status: \"error\", message: String(error) };\n }\n }\n\n private async processAction(plannerResult: PlannerResult): Promise<ContentResult> {\n const { action } = plannerResult;\n const reflection = plannerResult.evaluation !== undefined || plannerResult.memory !== undefined || plannerResult.nextGoal !== undefined\n ? { evaluation: plannerResult.evaluation, memory: plannerResult.memory, nextGoal: plannerResult.nextGoal }\n : undefined;\n\n const risk = assessRisk(action);\n if (risk === \"blocked\") {\n return { status: \"blocked\", action, message: `Blocked action: ${JSON.stringify(action)}`, reflection };\n }\n\n if (this.session.mode === \"human-approved\" && risk === \"review\") {\n return { status: \"needs_approval\", action, message: `Approval needed for ${action.type}`, reflection };\n }\n\n if (action.type === \"done\") {\n return { status: \"done\", action, message: action.reason, reflection };\n }\n\n const message = await executeAction(action);\n return { status: \"executed\", action, message, reflection };\n }\n\n private async delay(ms: number): Promise<void> {\n await new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n\nexport function createBrowserAgent(config: LibraryAgentConfig, events?: LibraryAgentEvents): BrowserAgent {\n return new BrowserAgent(config, events);\n}\n\nexport { createWebLLMBridge } from \"../core/webllm-bridge\";\nexport { parseAction, parsePlannerResult } from \"../shared/parse-action\";\nexport type { BrowserAgentWebLLMBridge, WebLLMEngineLike } from \"../core/webllm-bridge\";\n\nexport type {\n AgentAction,\n AgentMode,\n AgentSession,\n ContentResult,\n LibraryAgentConfig,\n LibraryAgentEvents,\n PlannerConfig,\n PlannerInput,\n PlannerKind,\n PlannerResult,\n RiskLevel\n} from \"../shared/contracts\";\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["input", "result"]
|
|
4
|
+
"sourcesContent": ["import type { AgentAction, PlannerResult } from \"./contracts\";\n\nexport const PARSE_FAILURE_PATTERN = /(No JSON|JSON parse error|Parsed value is not an object|Unknown or missing action type|Missing required field)/;\n\nconst VALID_TYPES = new Set([\n \"click\", \"type\", \"navigate\", \"extract\", \"scroll\", \"focus\", \"wait\", \"done\",\n]);\n\n/**\n * Extract the first complete JSON object from text using bracket counting.\n * More robust than regex: handles prose before/after JSON, and repairs\n * truncated output (e.g. when the model hits a token limit mid-JSON).\n */\nfunction extractFirstJsonObject(text: string): string | null {\n const start = text.indexOf(\"{\");\n if (start === -1) return null;\n\n let depth = 0;\n let inString = false;\n let escaped = false;\n\n for (let i = start; i < text.length; i++) {\n const ch = text[i];\n if (escaped) { escaped = false; continue; }\n if (ch === \"\\\\\" && inString) { escaped = true; continue; }\n if (ch === '\"') { inString = !inString; continue; }\n if (inString) continue;\n if (ch === \"{\") depth++;\n else if (ch === \"}\") {\n depth--;\n if (depth === 0) return text.slice(start, i + 1);\n }\n }\n\n // Truncated JSON (hit token limit mid-output) \u2014 close remaining open braces.\n if (depth > 0) {\n return text.slice(start) + \"}\".repeat(depth);\n }\n\n return null;\n}\n\n/**\n * Parse an AgentAction from raw LLM output.\n *\n * Handles bare JSON, markdown fences, and JSON embedded in prose.\n * Returns a \"done\" action if parsing fails, so the caller always gets a valid AgentAction.\n */\nexport function parseAction(raw: string): AgentAction {\n const fenceMatch = raw.match(/```(?:json)?\\s*([\\s\\S]*?)```/);\n const candidate = fenceMatch ? fenceMatch[1].trim() : raw.trim();\n\n const jsonStr = extractFirstJsonObject(candidate);\n if (!jsonStr) {\n return { type: \"done\", reason: `No JSON object found in: ${raw.slice(0, 120)}` };\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(jsonStr);\n } catch {\n return { type: \"done\", reason: `JSON parse error for: ${jsonStr.slice(0, 120)}` };\n }\n\n if (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n return { type: \"done\", reason: \"Parsed value is not an object\" };\n }\n\n const obj = parsed as Record<string, unknown>;\n if (typeof obj.type !== \"string\" || !VALID_TYPES.has(obj.type)) {\n return { type: \"done\", reason: `Unknown or missing action type: ${String(obj.type)}` };\n }\n\n const t = obj.type;\n if ((t === \"click\" || t === \"type\" || t === \"extract\" || t === \"focus\") && typeof obj.selector !== \"string\") {\n return { type: \"done\", reason: `Missing required field 'selector' for action type: ${t}` };\n }\n if (t === \"extract\" && typeof obj.label !== \"string\") {\n return { type: \"done\", reason: `Missing required field 'label' for action type: extract` };\n }\n if (t === \"type\" && typeof obj.text !== \"string\") {\n return { type: \"done\", reason: `Missing required field 'text' for action type: type` };\n }\n if (t === \"navigate\" && typeof obj.url !== \"string\") {\n return { type: \"done\", reason: `Missing required field 'url' for action type: navigate` };\n }\n if (t === \"scroll\" && typeof obj.deltaY !== \"number\") {\n return { type: \"done\", reason: `Missing required field 'deltaY' for action type: scroll` };\n }\n if (t === \"wait\" && typeof obj.ms !== \"number\") {\n return { type: \"done\", reason: `Missing required field 'ms' for action type: wait` };\n }\n if (t === \"done\" && typeof obj.reason !== \"string\") {\n return { type: \"done\", reason: `Missing required field 'reason' for action type: done` };\n }\n\n return obj as unknown as AgentAction;\n}\n\n/**\n * Parse a full PlannerResult from raw LLM output.\n *\n * Accepts the reflection+action format:\n * { \"evaluation\": \"...\", \"memory\": \"...\", \"nextGoal\": \"...\", \"action\": { ... } }\n * Also supports legacy `next_goal` key for backward compatibility.\n *\n * Also accepts a bare AgentAction for backward compatibility with simple bridges.\n */\nexport function parsePlannerResult(raw: string): PlannerResult {\n const fenceMatch = raw.match(/```(?:json)?\\s*([\\s\\S]*?)```/);\n const candidate = fenceMatch ? fenceMatch[1].trim() : raw.trim();\n\n const jsonStr = extractFirstJsonObject(candidate);\n if (!jsonStr) {\n return { action: { type: \"done\", reason: `No JSON found in: ${raw.slice(0, 120)}` } };\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(jsonStr);\n } catch {\n return { action: { type: \"done\", reason: `JSON parse error: ${jsonStr.slice(0, 120)}` } };\n }\n\n if (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n return { action: { type: \"done\", reason: \"Parsed value is not an object\" } };\n }\n\n const obj = parsed as Record<string, unknown>;\n\n // Full reflection format: { evaluation, memory, nextGoal, action }\n if (typeof obj.action === \"object\" && obj.action !== null) {\n const action = parseAction(JSON.stringify(obj.action));\n return {\n action,\n evaluation: typeof obj.evaluation === \"string\" ? obj.evaluation : undefined,\n memory: typeof obj.memory === \"string\" ? obj.memory : undefined,\n nextGoal:\n typeof obj.nextGoal === \"string\"\n ? obj.nextGoal\n : typeof obj.next_goal === \"string\"\n ? obj.next_goal\n : undefined,\n };\n }\n\n // Fallback: bare AgentAction (no reflection fields)\n return { action: parseAction(jsonStr) };\n}\n", "import type { AgentAction } from \"../shared/contracts\";\n\nfunction mustFind(selector: string): HTMLElement {\n const node = document.querySelector(selector);\n if (node instanceof HTMLElement) {\n return node;\n }\n\n // Fallback: if selector looks like a bare nth-of-type or is invalid,\n // try to find the element by tag and common attributes extracted from the selector\n const tagMatch = selector.match(/^(\\w+)/);\n if (tagMatch) {\n const tag = tagMatch[1];\n // Try matching by name, placeholder, or aria-label attributes in the selector\n const attrMatch = selector.match(/\\[(\\w[\\w-]*)=[\"']?([^\\]\"']+)[\"']?\\]/);\n if (attrMatch) {\n const fallback = document.querySelector(`${tag}[${attrMatch[1]}=\"${attrMatch[2]}\"]`);\n if (fallback instanceof HTMLElement) return fallback;\n }\n // Last resort: if only one element of that tag exists, use it\n const allOfTag = document.querySelectorAll(tag);\n if (allOfTag.length === 1 && allOfTag[0] instanceof HTMLElement) {\n return allOfTag[0];\n }\n }\n\n throw new Error(`Selector not found: ${selector}`);\n}\n\nfunction dispatchInputEvents(el: HTMLInputElement | HTMLTextAreaElement): void {\n el.dispatchEvent(new InputEvent(\"input\", { bubbles: true, cancelable: true }));\n el.dispatchEvent(new Event(\"change\", { bubbles: true }));\n}\n\nexport async function executeAction(action: AgentAction): Promise<string> {\n switch (action.type) {\n case \"click\": {\n const el = mustFind(action.selector);\n if ((el as HTMLButtonElement).disabled) {\n throw new Error(`Element is disabled: ${action.selector}`);\n }\n el.click();\n return `Clicked ${action.selector}`;\n }\n case \"type\": {\n const input = mustFind(action.selector) as HTMLInputElement | HTMLTextAreaElement;\n if (input.value === action.text) {\n return `Already contains correct value in ${action.selector}`;\n }\n input.focus();\n if (action.clearFirst) {\n input.value = \"\";\n dispatchInputEvents(input);\n }\n input.value = `${input.value}${action.text}`;\n dispatchInputEvents(input);\n if (input.value.indexOf(action.text) === -1) {\n throw new Error(`Type verification failed: value did not update for ${action.selector}`);\n }\n return `Typed into ${action.selector}`;\n }\n case \"navigate\": {\n window.location.href = action.url;\n return `Navigated to ${action.url}`;\n }\n case \"extract\": {\n const value = mustFind(action.selector).innerText.trim();\n if (!value) {\n throw new Error(`Extract returned empty text from ${action.selector}`);\n }\n return `${action.label}: ${value}`;\n }\n case \"scroll\": {\n const target = action.selector ? mustFind(action.selector) : document.documentElement;\n target.scrollBy({ top: action.deltaY, behavior: \"smooth\" });\n return `Scrolled ${action.deltaY > 0 ? \"down\" : \"up\"} ${Math.abs(action.deltaY)}px`;\n }\n case \"focus\": {\n mustFind(action.selector).focus();\n return `Focused ${action.selector}`;\n }\n case \"wait\": {\n await new Promise((resolve) => setTimeout(resolve, action.ms));\n return `Waited ${action.ms}ms`;\n }\n case \"done\": {\n return action.reason;\n }\n default:\n return \"No-op\";\n }\n}\n", "import type { CandidateElement, PageSnapshot } from \"../shared/contracts\";\n\nconst CANDIDATE_SELECTOR =\n \"a,button,input,textarea,select,[role='button'],[role='link'],[contenteditable='true']\";\n\nconst MAX_CANDIDATES = 60;\n\nfunction cssPath(element: Element): string {\n if (!(element instanceof HTMLElement)) {\n return element.tagName.toLowerCase();\n }\n\n if (element.id) {\n return `#${CSS.escape(element.id)}`;\n }\n\n // For form elements, prefer attribute-based selectors that are more stable\n const tag = element.tagName.toLowerCase();\n if (tag === \"input\" || tag === \"textarea\" || tag === \"select\") {\n const name = element.getAttribute(\"name\");\n if (name && document.querySelectorAll(`${tag}[name=${CSS.escape(name)}]`).length === 1) {\n return `${tag}[name=${CSS.escape(name)}]`;\n }\n const type = (element as HTMLInputElement).type;\n const placeholder = element.getAttribute(\"placeholder\");\n if (placeholder && document.querySelectorAll(`${tag}[placeholder=${CSS.escape(placeholder)}]`).length === 1) {\n return `${tag}[placeholder=${CSS.escape(placeholder)}]`;\n }\n const ariaLabel = element.getAttribute(\"aria-label\");\n if (ariaLabel && document.querySelectorAll(`${tag}[aria-label=${CSS.escape(ariaLabel)}]`).length === 1) {\n return `${tag}[aria-label=${CSS.escape(ariaLabel)}]`;\n }\n // Combine name + type for uniqueness\n if (name && type) {\n const combo = `${tag}[name=${CSS.escape(name)}][type=${CSS.escape(type)}]`;\n if (document.querySelectorAll(combo).length === 1) {\n return combo;\n }\n }\n }\n\n // For buttons/links, prefer text-based or aria selectors\n if (tag === \"button\" || tag === \"a\") {\n const ariaLabel = element.getAttribute(\"aria-label\");\n if (ariaLabel && document.querySelectorAll(`${tag}[aria-label=${CSS.escape(ariaLabel)}]`).length === 1) {\n return `${tag}[aria-label=${CSS.escape(ariaLabel)}]`;\n }\n }\n\n const parts: string[] = [];\n let current: HTMLElement | null = element;\n while (current && parts.length < 4) {\n let part = current.tagName.toLowerCase();\n if (current.classList.length > 0) {\n part += `.${Array.from(current.classList).slice(0, 2).map(CSS.escape).join(\".\")}`;\n }\n const parent: HTMLElement | null = current.parentElement;\n if (parent) {\n const siblings = Array.from(parent.children).filter((s: Element) => s.tagName === current!.tagName);\n if (siblings.length > 1) {\n const index = siblings.indexOf(current) + 1;\n part += `:nth-of-type(${index})`;\n }\n }\n parts.unshift(part);\n current = parent;\n }\n return parts.join(\" > \");\n}\n\nfunction isVisible(el: HTMLElement): boolean {\n const style = window.getComputedStyle(el);\n if (el.offsetParent === null && el.tagName !== \"BODY\" && style.position !== \"fixed\") return false;\n if (style.display === \"none\" || style.visibility === \"hidden\" || style.opacity === \"0\") return false;\n // Zero-dimension elements are functionally hidden\n const rect = el.getBoundingClientRect();\n return rect.width > 0 || rect.height > 0;\n}\n\nfunction isInViewport(el: HTMLElement): boolean {\n const rect = el.getBoundingClientRect();\n return (\n rect.bottom > 0 &&\n rect.top < window.innerHeight &&\n rect.right > 0 &&\n rect.left < window.innerWidth\n );\n}\n\nfunction isActiveElement(el: HTMLElement): boolean {\n if (el.classList.contains(\"active\")) return true;\n if (el.getAttribute(\"aria-selected\") === \"true\") return true;\n const ariaCurrent = el.getAttribute(\"aria-current\");\n if (ariaCurrent && ariaCurrent !== \"false\") return true;\n if (el.getAttribute(\"aria-pressed\") === \"true\") return true;\n return false;\n}\n\n/** Resolve the visible label text via for/id, aria-labelledby, aria-label, or wrapping <label>. */\nfunction getAssociatedLabel(el: HTMLElement): string {\n if (el.id) {\n const label = document.querySelector<HTMLLabelElement>(`label[for=\"${CSS.escape(el.id)}\"]`);\n if (label) return label.innerText.trim();\n }\n\n const labelledBy = el.getAttribute(\"aria-labelledby\");\n if (labelledBy) {\n const labelEl = document.getElementById(labelledBy);\n if (labelEl) return labelEl.innerText.trim();\n }\n\n const ariaLabel = el.getAttribute(\"aria-label\");\n if (ariaLabel) return ariaLabel.trim();\n\n const parentLabel = el.closest(\"label\");\n if (parentLabel) {\n return Array.from(parentLabel.childNodes)\n .filter((n) => n.nodeType === Node.TEXT_NODE)\n .map((n) => n.textContent?.trim() ?? \"\")\n .filter(Boolean)\n .join(\" \");\n }\n\n return \"\";\n}\n\nexport function collectSnapshot(): PageSnapshot {\n const allNodes = Array.from(\n document.querySelectorAll<HTMLElement>(CANDIDATE_SELECTOR)\n ).filter(isVisible).filter((el) => !el.closest(\"[data-agent-exclude]\"));\n\n // In-viewport elements first so the model sees the most relevant candidates first\n const inView = allNodes.filter(isInViewport);\n const offScreen = allNodes.filter((el) => !isInViewport(el));\n const nodes = [...inView, ...offScreen].slice(0, MAX_CANDIDATES);\n\n const candidates: CandidateElement[] = nodes.map((node) => {\n const placeholder =\n (node as HTMLInputElement).placeholder?.trim() || node.getAttribute(\"placeholder\")?.trim();\n const associatedLabel = getAssociatedLabel(node);\n return {\n selector: cssPath(node),\n role: node.getAttribute(\"role\") ?? node.tagName.toLowerCase(),\n text: (node.innerText || node.getAttribute(\"name\") || \"\").trim().slice(0, 120),\n placeholder: placeholder || undefined,\n label: associatedLabel || undefined,\n active: isActiveElement(node) || undefined,\n };\n });\n\n const textPreview = document.body.innerText.replace(/\\s+/g, \" \").trim().slice(0, 1500);\n\n return {\n url: window.location.href,\n title: document.title,\n textPreview,\n candidates,\n };\n}\n", "import type { AgentAction, CandidateElement, PlannerConfig, PlannerInput, PlannerResult } from \"../shared/contracts\";\n\ntype WebLLMBridge = {\n // Bridge may return PlannerResult (new), AgentAction (legacy), or raw LLM text.\n plan(input: PlannerInput, modelId?: string): Promise<PlannerResult | AgentAction | string>;\n // Optional retry hook that keeps chat history and asks for corrected JSON.\n retryInvalidJson?(input: PlannerInput, badOutput: string, modelId?: string): Promise<PlannerResult | AgentAction | string>;\n};\n\nconst URL_PATTERN = /(?:go to|navigate to|open)\\s+(https?:\\/\\/\\S+)/i;\nconst SEARCH_PATTERN = /search(?:\\s+for)?\\s+(.+)/i;\nconst FILL_PATTERN = /(?:fill|type|enter)\\s+\"?([^\"]+)\"?\\s+(?:in(?:to)?|for|on)\\s+(.+)/i;\nconst CLICK_PATTERN = /click(?:\\s+(?:on|the))?\\s+(.+)/i;\n\nfunction findByText(candidates: CandidateElement[], text: string): CandidateElement | undefined {\n const lower = text.toLowerCase();\n return candidates.find(\n (c) =>\n c.text.toLowerCase().includes(lower) ||\n (c.placeholder?.toLowerCase().includes(lower) ?? false) ||\n (c.label?.toLowerCase().includes(lower) ?? false)\n );\n}\n\nfunction findInput(candidates: CandidateElement[]): CandidateElement | undefined {\n return candidates.find(\n (c) => c.role === \"input\" || c.role === \"textarea\" || c.selector.includes(\"input\") || c.selector.includes(\"textarea\")\n );\n}\n\nfunction findButton(candidates: CandidateElement[]): CandidateElement | undefined {\n return candidates.find(\n (c) => c.role === \"button\" || c.role === \"a\" || c.selector.includes(\"button\") || c.selector.includes(\"a\")\n );\n}\n\nfunction heuristicPlan(input: PlannerInput): AgentAction {\n const { goal, snapshot, history } = input;\n\n const navMatch = goal.match(URL_PATTERN);\n if (navMatch) {\n return { type: \"navigate\", url: navMatch[1] };\n }\n\n const fillMatch = goal.match(FILL_PATTERN);\n if (fillMatch) {\n const [, text, fieldHint] = fillMatch;\n const target = findByText(snapshot.candidates, fieldHint) ?? findInput(snapshot.candidates);\n if (target) {\n return { type: \"type\", selector: target.selector, text, clearFirst: true, label: target.label || target.text || target.placeholder };\n }\n }\n\n const searchMatch = goal.match(SEARCH_PATTERN);\n if (searchMatch) {\n const input = findInput(snapshot.candidates);\n if (input) {\n return { type: \"type\", selector: input.selector, text: searchMatch[1].trim(), clearFirst: true, label: input.label || input.text || input.placeholder };\n }\n }\n\n const clickMatch = goal.match(CLICK_PATTERN);\n if (clickMatch) {\n const target = findByText(snapshot.candidates, clickMatch[1].trim());\n if (target) {\n return { type: \"click\", selector: target.selector, label: target.text };\n }\n }\n\n const firstInput = findInput(snapshot.candidates);\n const firstButton = findButton(snapshot.candidates);\n\n if (firstInput && !history.some((h) => h.startsWith(\"Typed\"))) {\n const searchTerm = goal.replace(/.*(?:search|find|look up)\\s+/i, \"\").trim();\n return { type: \"type\", selector: firstInput.selector, text: searchTerm, clearFirst: true, label: firstInput.label || firstInput.text || firstInput.placeholder };\n }\n\n if (firstButton && !history.some((h) => h.startsWith(\"Clicked\"))) {\n return { type: \"click\", selector: firstButton.selector, label: firstButton.text };\n }\n\n return { type: \"done\", reason: \"No further heuristic actions available\" };\n}\n\n/** Normalize whatever a bridge returns into a PlannerResult. */\nfunction toPlannerResult(raw: PlannerResult | AgentAction): PlannerResult {\n // New format: has an `action` key that is an object\n if (\"action\" in raw && typeof (raw as PlannerResult).action === \"object\") {\n return raw as PlannerResult;\n }\n // Legacy format: bare AgentAction\n return { action: raw as AgentAction };\n}\n\nasync function parsePlannerText(raw: string): Promise<{ result: PlannerResult; parseFailed: boolean }> {\n const { parsePlannerResult, PARSE_FAILURE_PATTERN } = await import(\"../shared/parse-action\");\n const result = parsePlannerResult(raw);\n const parseFailed = result.action.type === \"done\" && PARSE_FAILURE_PATTERN.test(result.action.reason);\n return { result, parseFailed };\n}\n\n\nasync function normalizeBridgeResponse(\n raw: PlannerResult | AgentAction | string\n): Promise<{ result: PlannerResult; parseFailed: boolean; rawText?: string }> {\n if (typeof raw === \"string\") {\n const { result, parseFailed } = await parsePlannerText(raw);\n return { result, parseFailed, rawText: raw };\n }\n\n return { result: toPlannerResult(raw), parseFailed: false };\n}\n\nexport async function planNextAction(config: PlannerConfig, input: PlannerInput): Promise<PlannerResult> {\n if (config.kind === \"heuristic\") {\n return { action: heuristicPlan(input) };\n }\n\n const bridge = (window as Window & { __browserAgentWebLLM?: WebLLMBridge }).__browserAgentWebLLM;\n if (!bridge) {\n return {\n action: {\n type: \"done\",\n reason: \"WebLLM bridge is not configured. Use heuristic mode or wire a WebLLM bridge implementation.\"\n }\n };\n }\n\n const plannerInput = { ...input, systemPrompt: config.systemPrompt };\n const firstAttempt = await normalizeBridgeResponse(await bridge.plan(plannerInput, config.modelId));\n\n if (!firstAttempt.parseFailed) {\n return firstAttempt.result;\n }\n\n if (bridge.retryInvalidJson && firstAttempt.rawText) {\n const retryAttempt = await normalizeBridgeResponse(\n await bridge.retryInvalidJson(plannerInput, firstAttempt.rawText, config.modelId)\n );\n\n if (!retryAttempt.parseFailed) {\n return retryAttempt.result;\n }\n }\n\n return {\n action: {\n type: \"done\",\n reason: \"WebLLM output could not be parsed after retry.\"\n }\n };\n}\n", "import type { AgentAction, CandidateElement, RiskLevel } from \"./contracts\";\n\nconst RISKY_KEYWORDS = /\\b(delete|remove|pay|purchase|submit|confirm|checkout|transfer|withdraw|send)\\b/i;\n\nfunction elementTextRisky(text?: string): boolean {\n return text != null && RISKY_KEYWORDS.test(text);\n}\n\nfunction candidateText(selector: string, candidates?: CandidateElement[]): string | undefined {\n const match = candidates?.find((c) => c.selector === selector);\n return match ? ([match.label, match.text, match.placeholder].filter(Boolean).join(\" \") || undefined) : undefined;\n}\n\nexport function assessRisk(action: AgentAction, candidates?: CandidateElement[]): RiskLevel {\n switch (action.type) {\n case \"navigate\": {\n // Fragment-only (#anchor) and relative paths are safe on-page navigations.\n if (action.url.startsWith(\"#\") || action.url.startsWith(\"/\") || action.url.startsWith(\"./\") || action.url.startsWith(\"../\")) {\n return \"safe\";\n }\n try {\n const next = new URL(action.url);\n if (![\"http:\", \"https:\"].includes(next.protocol)) {\n return \"blocked\";\n }\n } catch {\n // Unparseable URL that is not a known relative form \u2014 block it.\n return \"blocked\";\n }\n return \"safe\";\n }\n case \"click\": {\n const text = action.label ?? candidateText(action.selector, candidates) ?? action.selector;\n return elementTextRisky(text) ? \"review\" : \"safe\";\n }\n case \"type\": {\n const text = action.label ?? candidateText(action.selector, candidates) ?? action.selector;\n return elementTextRisky(text) ? \"review\" : \"safe\";\n }\n case \"focus\":\n case \"scroll\":\n case \"wait\":\n return \"safe\";\n case \"extract\":\n return \"review\";\n case \"done\":\n return \"safe\";\n default:\n return \"review\";\n }\n}\n", "import type { PlannerInput, PlannerResult } from \"../shared/contracts\";\nimport { parsePlannerResult, PARSE_FAILURE_PATTERN } from \"../shared/parse-action\";\nimport { buildSystemPrompt, buildUserMessage } from \"./prompt\";\n\nexport const INVALID_JSON_RETRY_MESSAGE = [\n \"Your reply was not valid JSON. Output ONLY a JSON object \u2014 no explanation, no markdown, no extra text.\",\n 'Required format: {\"evaluation\":\"...\",\"memory\":\"...\",\"nextGoal\":\"...\",\"action\":{\"type\":\"click\",\"selector\":\"EXACT_SELECTOR\",\"label\":\"...\"}}',\n].join(\"\\n\");\n\nconst BARE_ACTION_RETRY_MESSAGE = [\n \"Still not valid JSON. Output ONLY the action object. No evaluation, memory, or nextGoal fields.\",\n 'Example: {\"type\":\"type\",\"selector\":\"EXACT_SELECTOR_FROM_LIST\",\"text\":\"value\",\"clearFirst\":true}',\n 'Example: {\"type\":\"click\",\"selector\":\"EXACT_SELECTOR_FROM_LIST\",\"label\":\"button text\"}',\n].join(\"\\n\");\n\ntype ChatRole = \"system\" | \"user\" | \"assistant\";\n\ntype ChatMessage = {\n role: ChatRole;\n content: string;\n};\n\ntype CompletionRequest = {\n messages: ChatMessage[];\n temperature?: number;\n max_tokens?: number;\n model?: string;\n};\n\ntype CompletionResponse = {\n choices?: Array<{\n message?: {\n content?: unknown;\n };\n }>;\n};\n\nexport type WebLLMEngineLike = {\n chat: {\n completions: {\n create(request: CompletionRequest): Promise<CompletionResponse>;\n };\n };\n};\n\nexport type BrowserAgentWebLLMBridge = {\n plan(input: PlannerInput, modelId?: string): Promise<PlannerResult>;\n retryInvalidJson(input: PlannerInput, badOutput: string, modelId?: string): Promise<PlannerResult>;\n};\n\nfunction isParseFailure(result: PlannerResult): boolean {\n if (result.action.type !== \"done\") {\n return false;\n }\n\n const reason = result.action.reason;\n return PARSE_FAILURE_PATTERN.test(reason);\n}\n\nfunction contentToText(content: unknown): string {\n if (typeof content === \"string\") {\n return content;\n }\n\n if (Array.isArray(content)) {\n const chunks = content\n .map((part) => {\n if (typeof part === \"string\") {\n return part;\n }\n if (typeof part === \"object\" && part !== null && \"text\" in part && typeof part.text === \"string\") {\n return part.text;\n }\n return \"\";\n })\n .filter(Boolean);\n\n return chunks.join(\"\\n\");\n }\n\n return \"\";\n}\n\nfunction failureResult(attempts: number): PlannerResult {\n return {\n action: {\n type: \"done\",\n reason: `WebLLM returned invalid JSON after ${attempts} attempt${attempts === 1 ? \"\" : \"s\"}. Unable to continue.`\n }\n };\n}\n\nasync function createCompletion(engine: WebLLMEngineLike, messages: ChatMessage[], modelId?: string): Promise<string> {\n const response = await engine.chat.completions.create({\n messages,\n temperature: 0,\n max_tokens: 700,\n ...(modelId ? { model: modelId } : {})\n });\n\n return contentToText(response.choices?.[0]?.message?.content).trim();\n}\n\nfunction buildBaseMessages(input: PlannerInput): ChatMessage[] {\n return [\n { role: \"system\", content: buildSystemPrompt(input.systemPrompt) },\n { role: \"user\", content: buildUserMessage(input) }\n ];\n}\n\nasync function retryInvalidJsonWithHistory(\n engine: WebLLMEngineLike,\n baseMessages: ChatMessage[],\n badOutput: string,\n modelId?: string\n): Promise<PlannerResult> {\n // Attempt 2: improved message with format example\n const attempt2Messages: ChatMessage[] = [\n ...baseMessages,\n { role: \"assistant\", content: badOutput },\n { role: \"user\", content: INVALID_JSON_RETRY_MESSAGE }\n ];\n\n const raw2 = await createCompletion(engine, attempt2Messages, modelId);\n const result2 = parsePlannerResult(raw2);\n if (!isParseFailure(result2)) return result2;\n\n // Attempt 3: ask for bare action only (simpler target for small models)\n const attempt3Messages: ChatMessage[] = [\n ...attempt2Messages,\n { role: \"assistant\", content: raw2 },\n { role: \"user\", content: BARE_ACTION_RETRY_MESSAGE }\n ];\n\n const raw3 = await createCompletion(engine, attempt3Messages, modelId);\n const result3 = parsePlannerResult(raw3);\n if (!isParseFailure(result3)) return result3;\n\n return failureResult(3);\n}\n\nexport function createWebLLMBridge(engine: WebLLMEngineLike): BrowserAgentWebLLMBridge {\n return {\n async plan(input: PlannerInput, modelId?: string): Promise<PlannerResult> {\n const baseMessages = buildBaseMessages(input);\n\n // Attempt 1: normal\n const raw1 = await createCompletion(engine, baseMessages, modelId);\n const result1 = parsePlannerResult(raw1);\n if (!isParseFailure(result1)) return result1;\n\n // Attempts 2 & 3 with progressively simpler asks\n return retryInvalidJsonWithHistory(engine, baseMessages, raw1, modelId);\n },\n\n async retryInvalidJson(input: PlannerInput, badOutput: string, modelId?: string): Promise<PlannerResult> {\n const baseMessages = buildBaseMessages(input);\n return retryInvalidJsonWithHistory(engine, baseMessages, badOutput, modelId);\n }\n };\n}\n", "import type { CandidateElement, PlannerInput } from \"../shared/contracts\";\n\nconst MAX_TEXT_PREVIEW_LENGTH = 800;\n\nconst DEFAULT_SYSTEM_PROMPT = [\n \"You are OmniBrowser Agent, an on-page web automation planner.\",\n \"Choose exactly one next action using the provided page snapshot.\",\n \"\",\n \"Output rules:\",\n '- Reply with only one valid JSON object (no markdown fences, no prose).',\n '- JSON shape must be: { \"evaluation\": string, \"memory\": string, \"nextGoal\": string, \"action\": AgentAction }.',\n '- Keep evaluation/memory/nextGoal concise but informative.',\n \"\",\n \"Valid AgentAction shapes:\",\n '- {\"type\":\"click\",\"selector\":\"<css>\",\"label\":\"<optional>\"}',\n '- {\"type\":\"type\",\"selector\":\"<css>\",\"text\":\"<text>\",\"clearFirst\":true|false,\"label\":\"<optional>\"}',\n '- {\"type\":\"navigate\",\"url\":\"https://...\"}',\n '- {\"type\":\"extract\",\"selector\":\"<css>\",\"label\":\"<label>\"}',\n '- {\"type\":\"scroll\",\"selector\":\"<optional css>\",\"deltaY\":number}',\n '- {\"type\":\"focus\",\"selector\":\"<css>\"}',\n '- {\"type\":\"wait\",\"ms\":number}',\n '- {\"type\":\"done\",\"reason\":\"<reason>\"}',\n \"\",\n \"IMPORTANT: You MUST use selectors exactly as listed in the candidates. NEVER invent or guess selectors.\",\n \"If you cannot find a matching candidate for a target element, use the closest match from the candidates list.\",\n \"When previous step failed, recover by trying a different candidate selector or fallback strategy.\",\n \"NEVER use navigate for in-page tab switches or buttons \u2014 use click with the button's selector instead.\",\n \"\",\n \"Loop prevention rules (CRITICAL):\",\n \"- If a candidate shows 'state: active', it is already selected/active \u2014 do NOT click it again.\",\n \"- Check the History before acting. If the same selector was already clicked or typed in a recent step, do NOT repeat it \u2014 proceed to the next logical step or return done.\",\n \"- If the goal is already achieved (value is set, element clicked, task complete), return done immediately.\",\n \"- NEVER click a navigation tab or button more than once per goal unless the page changed to a different section.\"\n].join(\"\\n\");\n\nfunction formatCandidate(candidate: CandidateElement, index: number): string {\n const parts = [\n `${candidate.role || \"element\"}`,\n `selector: ${JSON.stringify(candidate.selector)}`,\n `text: ${JSON.stringify(candidate.text || \"\")}`\n ];\n\n if (candidate.label) {\n parts.push(`label: ${JSON.stringify(candidate.label)}`);\n }\n if (candidate.placeholder) {\n parts.push(`placeholder: ${JSON.stringify(candidate.placeholder)}`);\n }\n if (candidate.active) {\n parts.push(`state: active`);\n }\n\n return `[${index + 1}] ${parts.join(\" | \")}`;\n}\n\nexport function buildSystemPrompt(customPrompt?: string): string {\n if (!customPrompt?.trim()) {\n return DEFAULT_SYSTEM_PROMPT;\n }\n\n return `${DEFAULT_SYSTEM_PROMPT}\\n\\nAdditional instructions:\\n${customPrompt.trim()}`;\n}\n\nexport function buildUserMessage(input: PlannerInput): string {\n const { goal, snapshot, history, memory, lastError } = input;\n const candidates = snapshot.candidates.map(formatCandidate).join(\"\\n\");\n const historyLines = history.length > 0\n ? history.map((step, index) => `${index + 1}. ${step}`).join(\"\\n\")\n : \"(none)\";\n\n return [\n `Goal: ${goal}`,\n \"\",\n \"Page snapshot:\",\n `- URL: ${snapshot.url}`,\n `- Title: ${snapshot.title}`,\n `- Text preview (first ${MAX_TEXT_PREVIEW_LENGTH} chars): ${JSON.stringify(snapshot.textPreview.slice(0, MAX_TEXT_PREVIEW_LENGTH))}`,\n \"\",\n `Interactive candidates (${snapshot.candidates.length}):`,\n candidates || \"(none)\",\n \"\",\n \"History:\",\n historyLines,\n \"\",\n `Working memory: ${memory ? JSON.stringify(memory) : \"(none)\"}`,\n `Last error: ${lastError ? JSON.stringify(lastError) : \"(none)\"}`,\n \"If Last error is present, recover and choose a different valid action.\"\n ].join(\"\\n\");\n}\n", "import { executeAction } from \"../core/executor\";\nimport { collectSnapshot } from \"../core/observer\";\nimport { planNextAction } from \"../core/planner\";\nimport type {\n AgentAction,\n AgentSession,\n CandidateElement,\n ContentResult,\n LibraryAgentConfig,\n LibraryAgentEvents,\n PlannerConfig,\n PlannerResult\n} from \"../shared/contracts\";\nimport { assessRisk } from \"../shared/safety\";\n\nconst DEFAULT_PLANNER: PlannerConfig = { kind: \"heuristic\" };\n\n/** Max consecutive errors before the agent gives up instead of retrying */\nconst MAX_CONSECUTIVE_ERRORS = 2;\n\n/** Sliding window of recent action signatures used for loop detection */\nconst LOOP_WINDOW = 8;\nconst LOOP_THRESHOLD = 3;\n\nfunction actionSignature(action: AgentAction): string | null {\n if (action.type === \"click\" || action.type === \"type\" || action.type === \"focus\") {\n return `${action.type}:${action.selector}`;\n }\n return null;\n}\n\nexport class BrowserAgent {\n private session: AgentSession;\n private maxSteps: number;\n private stepDelayMs: number;\n private events: LibraryAgentEvents;\n private isStopped = false;\n private signal?: AbortSignal;\n private recentActionSigs: string[] = [];\n\n constructor(config: LibraryAgentConfig, events: LibraryAgentEvents = {}) {\n this.session = {\n id: crypto.randomUUID(),\n tabId: null,\n goal: config.goal,\n mode: config.mode ?? \"human-approved\",\n planner: config.planner ?? DEFAULT_PLANNER,\n history: [],\n isRunning: false\n };\n\n this.maxSteps = config.maxSteps ?? 20;\n this.stepDelayMs = config.stepDelayMs ?? 500;\n this.events = events;\n this.signal = config.signal;\n }\n\n getSession(): AgentSession {\n return { ...this.session, history: [...this.session.history] };\n }\n\n get isRunning(): boolean {\n return this.session.isRunning;\n }\n\n get hasPendingAction(): boolean {\n return this.session.pendingAction != null;\n }\n\n async start(): Promise<ContentResult> {\n this.isStopped = false;\n this.recentActionSigs = [];\n this.session.isRunning = true;\n this.events.onStart?.(this.getSession());\n return this.runLoop();\n }\n\n async resume(): Promise<ContentResult> {\n if (this.session.pendingAction) {\n const approvalResult = await this.approvePendingAction();\n if (approvalResult.status === \"error\") {\n return approvalResult;\n }\n }\n this.session.isRunning = true;\n return this.runLoop();\n }\n\n private async runLoop(): Promise<ContentResult> {\n let consecutiveErrors = 0;\n let lastError: string | undefined;\n\n for (let step = 0; step < this.maxSteps; step += 1) {\n if (this.isStopped || !this.session.isRunning) {\n return { status: \"done\", message: \"Stopped\" };\n }\n\n if (this.signal?.aborted) {\n this.session.isRunning = false;\n return { status: \"done\", message: \"Aborted\" };\n }\n\n const result = await this.tick(lastError);\n this.events.onStep?.(result, this.getSession());\n\n if (result.status === \"error\") {\n consecutiveErrors += 1;\n lastError = result.message;\n this.session.history.push(`Error: ${result.message}`);\n\n if (consecutiveErrors >= MAX_CONSECUTIVE_ERRORS) {\n this.session.isRunning = false;\n this.events.onError?.(new Error(result.message), this.getSession());\n this.events.onDone?.(result, this.getSession());\n return result;\n }\n\n await this.delay(this.stepDelayMs);\n continue;\n }\n\n consecutiveErrors = 0;\n lastError = undefined;\n this.session.history.push(result.message);\n\n if (result.status === \"needs_approval\") {\n this.session.pendingAction = result.action;\n this.session.isRunning = false;\n if (result.action) {\n this.events.onApprovalRequired?.(result.action, this.getSession());\n }\n return result;\n }\n\n if ([\"done\", \"blocked\"].includes(result.status)) {\n this.session.isRunning = false;\n this.events.onDone?.(result, this.getSession());\n return result;\n }\n\n await this.delay(this.stepDelayMs);\n }\n\n const result: ContentResult = { status: \"done\", message: \"Reached max steps\" };\n this.session.history.push(result.message);\n this.session.isRunning = false;\n this.events.onMaxStepsReached?.(this.getSession());\n this.events.onDone?.(result, this.getSession());\n return result;\n }\n\n async approvePendingAction(): Promise<ContentResult> {\n if (!this.session.pendingAction) {\n return { status: \"error\", message: \"No pending action to approve\" };\n }\n\n try {\n const message = await executeAction(this.session.pendingAction);\n const result: ContentResult = {\n status: \"executed\",\n message,\n action: this.session.pendingAction\n };\n this.session.history.push(message);\n this.session.pendingAction = undefined;\n this.session.isRunning = true;\n this.events.onStep?.(result, this.getSession());\n return result;\n } catch (error) {\n this.session.isRunning = false;\n this.events.onError?.(error, this.getSession());\n return { status: \"error\", message: String(error) };\n }\n }\n\n stop(): void {\n this.isStopped = true;\n this.session.isRunning = false;\n }\n\n private async tick(lastError?: string): Promise<ContentResult> {\n try {\n const snapshot = collectSnapshot();\n const plannerResult = await planNextAction(this.session.planner, {\n goal: this.session.goal,\n snapshot,\n history: this.session.history,\n lastError,\n memory: this.session.memory\n });\n\n // Carry working memory forward across steps\n if (plannerResult.memory !== undefined) {\n this.session.memory = plannerResult.memory;\n }\n\n return this.processAction(plannerResult, snapshot.candidates);\n } catch (error) {\n return { status: \"error\", message: String(error) };\n }\n }\n\n private async processAction(plannerResult: PlannerResult, candidates?: CandidateElement[]): Promise<ContentResult> {\n const { action } = plannerResult;\n const reflection = plannerResult.evaluation !== undefined || plannerResult.memory !== undefined || plannerResult.nextGoal !== undefined\n ? { evaluation: plannerResult.evaluation, memory: plannerResult.memory, nextGoal: plannerResult.nextGoal }\n : undefined;\n\n // Loop detection: if the same selector+action type appears LOOP_THRESHOLD times\n // in the recent window, the agent is stuck \u2014 force done rather than repeat.\n const sig = actionSignature(action);\n if (sig) {\n this.recentActionSigs.push(sig);\n if (this.recentActionSigs.length > LOOP_WINDOW) {\n this.recentActionSigs.shift();\n }\n const repeatCount = this.recentActionSigs.filter((s) => s === sig).length;\n if (repeatCount >= LOOP_THRESHOLD) {\n return {\n status: \"done\",\n action,\n message: \"Loop detected \u2014 goal appears to be complete.\",\n reflection\n };\n }\n }\n\n const risk = assessRisk(action, candidates);\n if (risk === \"blocked\") {\n return { status: \"blocked\", action, message: `Blocked action: ${JSON.stringify(action)}`, reflection };\n }\n\n if (this.session.mode === \"human-approved\" && risk === \"review\") {\n return { status: \"needs_approval\", action, message: `Approval needed for ${action.type}`, reflection };\n }\n\n if (action.type === \"done\") {\n return { status: \"done\", action, message: action.reason, reflection };\n }\n\n const message = await executeAction(action);\n return { status: \"executed\", action, message, reflection };\n }\n\n private async delay(ms: number): Promise<void> {\n await new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n\nexport function createBrowserAgent(config: LibraryAgentConfig, events?: LibraryAgentEvents): BrowserAgent {\n return new BrowserAgent(config, events);\n}\n\nexport { createWebLLMBridge } from \"../core/webllm-bridge\";\nexport { parseAction, parsePlannerResult } from \"../shared/parse-action\";\nexport type { BrowserAgentWebLLMBridge, WebLLMEngineLike } from \"../core/webllm-bridge\";\n\nexport type {\n AgentAction,\n AgentMode,\n AgentSession,\n ContentResult,\n LibraryAgentConfig,\n LibraryAgentEvents,\n PlannerConfig,\n PlannerInput,\n PlannerKind,\n PlannerResult,\n RiskLevel\n} from \"../shared/contracts\";\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["input", "parsePlannerResult", "PARSE_FAILURE_PATTERN", "result"]
|
|
7
7
|
}
|
package/dist/manifest.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"manifest_version": 3,
|
|
3
3
|
"name": "OmniBrowser Agent",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.35",
|
|
5
5
|
"description": "Local-first AI browser operator — heuristic and WebLLM planners.",
|
|
6
6
|
"permissions": ["activeTab", "tabs", "scripting", "storage"],
|
|
7
7
|
"host_permissions": ["http://*/*", "https://*/*"],
|
|
@@ -39,6 +39,8 @@ export interface CandidateElement {
|
|
|
39
39
|
placeholder?: string;
|
|
40
40
|
/** Associated <label> text resolved via for/id, aria-labelledby, aria-label, or wrapping <label> */
|
|
41
41
|
label?: string;
|
|
42
|
+
/** True when the element is currently active/selected (has .active class, aria-selected, aria-current, or aria-pressed) */
|
|
43
|
+
active?: boolean;
|
|
42
44
|
}
|
|
43
45
|
export interface PageSnapshot {
|
|
44
46
|
url: string;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type { AgentAction, RiskLevel } from "./contracts";
|
|
2
|
-
export declare function assessRisk(action: AgentAction): RiskLevel;
|
|
1
|
+
import type { AgentAction, CandidateElement, RiskLevel } from "./contracts";
|
|
2
|
+
export declare function assessRisk(action: AgentAction, candidates?: CandidateElement[]): RiskLevel;
|
package/icons/big.png
ADDED
|
Binary file
|
package/icons/logo.png
ADDED
|
Binary file
|
|
Binary file
|
package/notebook/.env
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
HF_TOKEN=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
|