@akshayram1/omnibrowser-agent 0.2.32 → 0.3.1
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 +65 -15
- package/dist/content.js.map +3 -3
- package/dist/lib.js +109 -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 +4 -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,19 +319,22 @@ 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);
|
|
291
326
|
const candidates = nodes.map((node) => {
|
|
292
327
|
const placeholder = node.placeholder?.trim() || node.getAttribute("placeholder")?.trim();
|
|
328
|
+
const controlValue = node instanceof HTMLInputElement || node instanceof HTMLTextAreaElement || node instanceof HTMLSelectElement ? String(node.value ?? "").trim().slice(0, 120) : void 0;
|
|
293
329
|
const associatedLabel = getAssociatedLabel(node);
|
|
294
330
|
return {
|
|
295
331
|
selector: cssPath(node),
|
|
296
332
|
role: node.getAttribute("role") ?? node.tagName.toLowerCase(),
|
|
297
333
|
text: (node.innerText || node.getAttribute("name") || "").trim().slice(0, 120),
|
|
334
|
+
value: controlValue,
|
|
298
335
|
placeholder: placeholder || void 0,
|
|
299
|
-
label: associatedLabel || void 0
|
|
336
|
+
label: associatedLabel || void 0,
|
|
337
|
+
active: isActiveElement(node) || void 0
|
|
300
338
|
};
|
|
301
339
|
});
|
|
302
340
|
const textPreview = document.body.innerText.replace(/\s+/g, " ").trim().slice(0, 1500);
|
|
@@ -375,14 +413,15 @@ function toPlannerResult(raw) {
|
|
|
375
413
|
return { action: raw };
|
|
376
414
|
}
|
|
377
415
|
async function parsePlannerText(raw) {
|
|
378
|
-
const
|
|
379
|
-
|
|
416
|
+
const { parsePlannerResult: parsePlannerResult2, PARSE_FAILURE_PATTERN: PARSE_FAILURE_PATTERN2 } = await Promise.resolve().then(() => (init_parse_action(), parse_action_exports));
|
|
417
|
+
const result = parsePlannerResult2(raw);
|
|
418
|
+
const parseFailed = result.action.type === "done" && PARSE_FAILURE_PATTERN2.test(result.action.reason);
|
|
419
|
+
return { result, parseFailed };
|
|
380
420
|
}
|
|
381
421
|
async function normalizeBridgeResponse(raw) {
|
|
382
422
|
if (typeof raw === "string") {
|
|
383
|
-
const
|
|
384
|
-
|
|
385
|
-
return { result: parsed, parseFailed, rawText: raw };
|
|
423
|
+
const { result, parseFailed } = await parsePlannerText(raw);
|
|
424
|
+
return { result, parseFailed, rawText: raw };
|
|
386
425
|
}
|
|
387
426
|
return { result: toPlannerResult(raw), parseFailed: false };
|
|
388
427
|
}
|
|
@@ -425,9 +464,16 @@ var RISKY_KEYWORDS = /\b(delete|remove|pay|purchase|submit|confirm|checkout|tran
|
|
|
425
464
|
function elementTextRisky(text) {
|
|
426
465
|
return text != null && RISKY_KEYWORDS.test(text);
|
|
427
466
|
}
|
|
428
|
-
function
|
|
467
|
+
function candidateText(selector, candidates) {
|
|
468
|
+
const match = candidates?.find((c) => c.selector === selector);
|
|
469
|
+
return match ? [match.label, match.text, match.placeholder].filter(Boolean).join(" ") || void 0 : void 0;
|
|
470
|
+
}
|
|
471
|
+
function assessRisk(action, candidates) {
|
|
429
472
|
switch (action.type) {
|
|
430
473
|
case "navigate": {
|
|
474
|
+
if (action.url.startsWith("#") || action.url.startsWith("/") || action.url.startsWith("./") || action.url.startsWith("../")) {
|
|
475
|
+
return "safe";
|
|
476
|
+
}
|
|
431
477
|
try {
|
|
432
478
|
const next = new URL(action.url);
|
|
433
479
|
if (!["http:", "https:"].includes(next.protocol)) {
|
|
@@ -438,10 +484,14 @@ function assessRisk(action) {
|
|
|
438
484
|
}
|
|
439
485
|
return "safe";
|
|
440
486
|
}
|
|
441
|
-
case "click":
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
487
|
+
case "click": {
|
|
488
|
+
const text = action.label ?? candidateText(action.selector, candidates) ?? action.selector;
|
|
489
|
+
return elementTextRisky(text) ? "review" : "safe";
|
|
490
|
+
}
|
|
491
|
+
case "type": {
|
|
492
|
+
const text = action.label ?? candidateText(action.selector, candidates) ?? action.selector;
|
|
493
|
+
return elementTextRisky(text) ? "review" : "safe";
|
|
494
|
+
}
|
|
445
495
|
case "focus":
|
|
446
496
|
case "scroll":
|
|
447
497
|
case "wait":
|
|
@@ -480,8 +530,16 @@ var DEFAULT_SYSTEM_PROMPT = [
|
|
|
480
530
|
'- {"type":"done","reason":"<reason>"}',
|
|
481
531
|
"",
|
|
482
532
|
"IMPORTANT: You MUST use selectors exactly as listed in the candidates. NEVER invent or guess selectors.",
|
|
533
|
+
"For form controls, candidate `value` is the current filled value. `placeholder` is only hint text and does NOT mean the field is filled.",
|
|
483
534
|
"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."
|
|
535
|
+
"When previous step failed, recover by trying a different candidate selector or fallback strategy.",
|
|
536
|
+
"NEVER use navigate for in-page tab switches or buttons \u2014 use click with the button's selector instead.",
|
|
537
|
+
"",
|
|
538
|
+
"Loop prevention rules (CRITICAL):",
|
|
539
|
+
"- If a candidate shows 'state: active', it is already selected/active \u2014 do NOT click it again.",
|
|
540
|
+
"- 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.",
|
|
541
|
+
"- If the goal is already achieved (value is set, element clicked, task complete), return done immediately.",
|
|
542
|
+
"- NEVER click a navigation tab or button more than once per goal unless the page changed to a different section."
|
|
485
543
|
].join("\n");
|
|
486
544
|
function formatCandidate(candidate, index) {
|
|
487
545
|
const parts = [
|
|
@@ -492,9 +550,15 @@ function formatCandidate(candidate, index) {
|
|
|
492
550
|
if (candidate.label) {
|
|
493
551
|
parts.push(`label: ${JSON.stringify(candidate.label)}`);
|
|
494
552
|
}
|
|
553
|
+
if (candidate.value !== void 0) {
|
|
554
|
+
parts.push(`value: ${JSON.stringify(candidate.value)}`);
|
|
555
|
+
}
|
|
495
556
|
if (candidate.placeholder) {
|
|
496
557
|
parts.push(`placeholder: ${JSON.stringify(candidate.placeholder)}`);
|
|
497
558
|
}
|
|
559
|
+
if (candidate.active) {
|
|
560
|
+
parts.push(`state: active`);
|
|
561
|
+
}
|
|
498
562
|
return `[${index + 1}] ${parts.join(" | ")}`;
|
|
499
563
|
}
|
|
500
564
|
function buildSystemPrompt(customPrompt) {
|
|
@@ -545,7 +609,7 @@ function isParseFailure(result) {
|
|
|
545
609
|
return false;
|
|
546
610
|
}
|
|
547
611
|
const reason = result.action.reason;
|
|
548
|
-
return
|
|
612
|
+
return PARSE_FAILURE_PATTERN.test(reason);
|
|
549
613
|
}
|
|
550
614
|
function contentToText(content) {
|
|
551
615
|
if (typeof content === "string") {
|
|
@@ -627,6 +691,14 @@ function createWebLLMBridge(engine) {
|
|
|
627
691
|
init_parse_action();
|
|
628
692
|
var DEFAULT_PLANNER = { kind: "heuristic" };
|
|
629
693
|
var MAX_CONSECUTIVE_ERRORS = 2;
|
|
694
|
+
var LOOP_WINDOW = 8;
|
|
695
|
+
var LOOP_THRESHOLD = 3;
|
|
696
|
+
function actionSignature(action) {
|
|
697
|
+
if (action.type === "click" || action.type === "type" || action.type === "focus") {
|
|
698
|
+
return `${action.type}:${action.selector}`;
|
|
699
|
+
}
|
|
700
|
+
return null;
|
|
701
|
+
}
|
|
630
702
|
var BrowserAgent = class {
|
|
631
703
|
session;
|
|
632
704
|
maxSteps;
|
|
@@ -634,6 +706,7 @@ var BrowserAgent = class {
|
|
|
634
706
|
events;
|
|
635
707
|
isStopped = false;
|
|
636
708
|
signal;
|
|
709
|
+
recentActionSigs = [];
|
|
637
710
|
constructor(config, events = {}) {
|
|
638
711
|
this.session = {
|
|
639
712
|
id: crypto.randomUUID(),
|
|
@@ -660,6 +733,7 @@ var BrowserAgent = class {
|
|
|
660
733
|
}
|
|
661
734
|
async start() {
|
|
662
735
|
this.isStopped = false;
|
|
736
|
+
this.recentActionSigs = [];
|
|
663
737
|
this.session.isRunning = true;
|
|
664
738
|
this.events.onStart?.(this.getSession());
|
|
665
739
|
return this.runLoop();
|
|
@@ -764,15 +838,31 @@ var BrowserAgent = class {
|
|
|
764
838
|
if (plannerResult.memory !== void 0) {
|
|
765
839
|
this.session.memory = plannerResult.memory;
|
|
766
840
|
}
|
|
767
|
-
return this.processAction(plannerResult);
|
|
841
|
+
return this.processAction(plannerResult, snapshot.candidates);
|
|
768
842
|
} catch (error) {
|
|
769
843
|
return { status: "error", message: String(error) };
|
|
770
844
|
}
|
|
771
845
|
}
|
|
772
|
-
async processAction(plannerResult) {
|
|
846
|
+
async processAction(plannerResult, candidates) {
|
|
773
847
|
const { action } = plannerResult;
|
|
774
848
|
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
|
|
849
|
+
const sig = actionSignature(action);
|
|
850
|
+
if (sig) {
|
|
851
|
+
this.recentActionSigs.push(sig);
|
|
852
|
+
if (this.recentActionSigs.length > LOOP_WINDOW) {
|
|
853
|
+
this.recentActionSigs.shift();
|
|
854
|
+
}
|
|
855
|
+
const repeatCount = this.recentActionSigs.filter((s) => s === sig).length;
|
|
856
|
+
if (repeatCount >= LOOP_THRESHOLD) {
|
|
857
|
+
return {
|
|
858
|
+
status: "done",
|
|
859
|
+
action,
|
|
860
|
+
message: "Loop detected \u2014 goal appears to be complete.",
|
|
861
|
+
reflection
|
|
862
|
+
};
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
const risk = assessRisk(action, candidates);
|
|
776
866
|
if (risk === "blocked") {
|
|
777
867
|
return { status: "blocked", action, message: `Blocked action: ${JSON.stringify(action)}`, reflection };
|
|
778
868
|
}
|
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 controlValue =\n node instanceof HTMLInputElement || node instanceof HTMLTextAreaElement || node instanceof HTMLSelectElement\n ? String(node.value ?? \"\").trim().slice(0, 120)\n : undefined;\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 value: controlValue,\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 \"For form controls, candidate `value` is the current filled value. `placeholder` is only hint text and does NOT mean the field is filled.\",\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.value !== undefined) {\n parts.push(`value: ${JSON.stringify(candidate.value)}`);\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://*/*"],
|
|
@@ -36,9 +36,13 @@ export interface CandidateElement {
|
|
|
36
36
|
selector: string;
|
|
37
37
|
role: string;
|
|
38
38
|
text: string;
|
|
39
|
+
/** Current control value for inputs/textarea/select (if any). */
|
|
40
|
+
value?: string;
|
|
39
41
|
placeholder?: string;
|
|
40
42
|
/** Associated <label> text resolved via for/id, aria-labelledby, aria-label, or wrapping <label> */
|
|
41
43
|
label?: string;
|
|
44
|
+
/** True when the element is currently active/selected (has .active class, aria-selected, aria-current, or aria-pressed) */
|
|
45
|
+
active?: boolean;
|
|
42
46
|
}
|
|
43
47
|
export interface PageSnapshot {
|
|
44
48
|
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
|