@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/.env
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
HF_TOKEN=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
|
package/README.github.md
CHANGED
|
@@ -165,6 +165,43 @@ See [docs/EMBEDDING.md](docs/EMBEDDING.md) for the full WebLLM bridge wiring gui
|
|
|
165
165
|
|
|
166
166
|
Model availability can vary by WebLLM release/build; if one fails to load, use a smaller fallback like `Llama-3.2-1B-Instruct-q4f16_1-MLC`.
|
|
167
167
|
|
|
168
|
+
### Bring Your Own Model (Colab + MLC)
|
|
169
|
+
|
|
170
|
+
Use the notebook workflow to fine-tune and quantize a planner model for OmniBrowser:
|
|
171
|
+
|
|
172
|
+
- [Notebook assets](notebook/README.md)
|
|
173
|
+
- [Google Colab notebook](notebook/custom_quantized_llm_colab.ipynb)
|
|
174
|
+
- [Starter dataset JSONL](notebook/data/omnibrowser_planner_train.jsonl)
|
|
175
|
+
|
|
176
|
+
The workflow:
|
|
177
|
+
|
|
178
|
+
1. Generate/expand a dataset in OmniBrowser prompt format (`notebook/scripts/generate_dataset.mjs`).
|
|
179
|
+
2. Validate selector + action correctness (`notebook/scripts/validate_dataset.mjs`).
|
|
180
|
+
3. QLoRA fine-tune `Qwen/Qwen2.5-1.5B-Instruct` in Colab.
|
|
181
|
+
4. Merge and quantize with `mlc_llm convert_weight --quantization q4f16_1`.
|
|
182
|
+
5. Upload to Hugging Face and load in WebLLM via custom `appConfig`.
|
|
183
|
+
|
|
184
|
+
```ts
|
|
185
|
+
import * as webllm from "@mlc-ai/web-llm";
|
|
186
|
+
import { createWebLLMBridge } from "@akshayram1/omnibrowser-agent";
|
|
187
|
+
|
|
188
|
+
const appConfig: webllm.AppConfig = {
|
|
189
|
+
model_list: [
|
|
190
|
+
{
|
|
191
|
+
model: "https://huggingface.co/your-account/omnibrowser-planner-q4f16_1-MLC",
|
|
192
|
+
model_id: "omnibrowser-planner-q4f16_1",
|
|
193
|
+
model_lib:
|
|
194
|
+
webllm.modelLibURLPrefix +
|
|
195
|
+
webllm.modelVersion +
|
|
196
|
+
"/Qwen2.5-1.5B-Instruct-q4f16_1-ctx4k_cs1k-webgpu.wasm",
|
|
197
|
+
},
|
|
198
|
+
],
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
const engine = await webllm.CreateMLCEngine("omnibrowser-planner-q4f16_1", { appConfig });
|
|
202
|
+
window.__browserAgentWebLLM = createWebLLMBridge(engine);
|
|
203
|
+
```
|
|
204
|
+
|
|
168
205
|
---
|
|
169
206
|
|
|
170
207
|
## Agent modes
|
package/demo1.gif
ADDED
|
Binary file
|
package/dist/background.js
CHANGED
|
@@ -52,7 +52,7 @@ async function tick(tabId) {
|
|
|
52
52
|
session.isRunning = false;
|
|
53
53
|
return;
|
|
54
54
|
}
|
|
55
|
-
setTimeout(() => tick(tabId),
|
|
55
|
+
setTimeout(() => tick(tabId), 500);
|
|
56
56
|
}
|
|
57
57
|
chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
|
|
58
58
|
if (message.type === "START_AGENT") {
|
package/dist/background.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/background/index.ts"],
|
|
4
|
-
"sourcesContent": ["import type { AgentMode, AgentSession, PlannerConfig } from \"../shared/contracts\";\n\nconst sessions = new Map<number, AgentSession>();\n\nfunction normalizePlannerConfig(rawPlanner: unknown): PlannerConfig {\n if (typeof rawPlanner === \"string\" && (rawPlanner === \"heuristic\" || rawPlanner === \"webllm\")) {\n return { kind: rawPlanner };\n }\n\n if (typeof rawPlanner === \"object\" && rawPlanner !== null) {\n const record = rawPlanner as Record<string, unknown>;\n const kind = record.kind;\n if (kind === \"heuristic\" || kind === \"webllm\") {\n return {\n kind,\n modelId: typeof record.modelId === \"string\" && record.modelId.trim() ? record.modelId : undefined,\n systemPrompt: typeof record.systemPrompt === \"string\" && record.systemPrompt.trim() ? record.systemPrompt : undefined\n };\n }\n }\n\n return { kind: \"heuristic\" };\n}\n\nfunction makeSession(tabId: number, goal: string, mode: AgentMode, planner: PlannerConfig): AgentSession {\n return {\n id: crypto.randomUUID(),\n tabId: tabId,\n goal,\n mode,\n planner,\n history: [],\n isRunning: true\n };\n}\n\nasync function tick(tabId: number) {\n const session = sessions.get(tabId);\n if (!session || !session.isRunning) {\n return;\n }\n\n const result = await chrome.tabs.sendMessage(tabId, {\n type: \"AGENT_TICK\",\n session\n });\n\n session.history.push(result.message);\n if (result.reflection?.memory !== undefined) {\n session.memory = result.reflection.memory;\n }\n session.lastError = result.status === \"error\" ? result.message : undefined;\n\n if (result.status === \"needs_approval\") {\n session.pendingAction = result.action;\n session.isRunning = false;\n return;\n }\n\n session.pendingAction = undefined;\n\n if ([\"done\", \"blocked\", \"error\"].includes(result.status)) {\n session.isRunning = false;\n return;\n }\n\n setTimeout(() => tick(tabId),
|
|
4
|
+
"sourcesContent": ["import type { AgentMode, AgentSession, PlannerConfig } from \"../shared/contracts\";\n\nconst sessions = new Map<number, AgentSession>();\n\nfunction normalizePlannerConfig(rawPlanner: unknown): PlannerConfig {\n if (typeof rawPlanner === \"string\" && (rawPlanner === \"heuristic\" || rawPlanner === \"webllm\")) {\n return { kind: rawPlanner };\n }\n\n if (typeof rawPlanner === \"object\" && rawPlanner !== null) {\n const record = rawPlanner as Record<string, unknown>;\n const kind = record.kind;\n if (kind === \"heuristic\" || kind === \"webllm\") {\n return {\n kind,\n modelId: typeof record.modelId === \"string\" && record.modelId.trim() ? record.modelId : undefined,\n systemPrompt: typeof record.systemPrompt === \"string\" && record.systemPrompt.trim() ? record.systemPrompt : undefined\n };\n }\n }\n\n return { kind: \"heuristic\" };\n}\n\nfunction makeSession(tabId: number, goal: string, mode: AgentMode, planner: PlannerConfig): AgentSession {\n return {\n id: crypto.randomUUID(),\n tabId: tabId,\n goal,\n mode,\n planner,\n history: [],\n isRunning: true\n };\n}\n\nasync function tick(tabId: number) {\n const session = sessions.get(tabId);\n if (!session || !session.isRunning) {\n return;\n }\n\n const result = await chrome.tabs.sendMessage(tabId, {\n type: \"AGENT_TICK\",\n session\n });\n\n session.history.push(result.message);\n if (result.reflection?.memory !== undefined) {\n session.memory = result.reflection.memory;\n }\n session.lastError = result.status === \"error\" ? result.message : undefined;\n\n if (result.status === \"needs_approval\") {\n session.pendingAction = result.action;\n session.isRunning = false;\n return;\n }\n\n session.pendingAction = undefined;\n\n if ([\"done\", \"blocked\", \"error\"].includes(result.status)) {\n session.isRunning = false;\n return;\n }\n\n setTimeout(() => tick(tabId), 500);\n}\n\nchrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {\n if (message.type === \"START_AGENT\") {\n const session = makeSession(message.tabId, message.goal, message.mode, normalizePlannerConfig(message.planner));\n sessions.set(message.tabId, session);\n tick(message.tabId).catch((error) => {\n const failed = sessions.get(message.tabId);\n if (failed) {\n failed.history.push(`Error: ${String(error)}`);\n failed.isRunning = false;\n }\n });\n sendResponse({ ok: true });\n return true;\n }\n\n if (message.type === \"APPROVE_ACTION\") {\n const session = sessions.get(message.tabId);\n if (!session) {\n sendResponse({ ok: false, error: \"No active session\" });\n return true;\n }\n\n session.isRunning = true;\n tick(message.tabId).catch((error) => {\n session.history.push(`Error: ${String(error)}`);\n session.isRunning = false;\n });\n sendResponse({ ok: true });\n return true;\n }\n\n if (message.type === \"STOP_AGENT\") {\n const session = sessions.get(message.tabId);\n if (session) {\n session.isRunning = false;\n }\n chrome.tabs.sendMessage(message.tabId, { type: \"AGENT_STOP\" }).catch(() => undefined);\n sendResponse({ ok: true });\n return true;\n }\n\n if (message.type === \"GET_STATUS\") {\n const lines = Array.from(sessions.values()).map(\n (session) =>\n `${session.isRunning ? \"RUNNING\" : \"IDLE\"} ${session.tabId}: ${session.goal.slice(0, 45)}${session.goal.length > 45 ? \"...\" : \"\"}`\n );\n\n sendResponse({ status: lines.length > 0 ? lines.join(\"\\n\") : \"Idle\" });\n return true;\n }\n\n return false;\n});\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/content.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",
|
|
@@ -118,9 +142,16 @@ var RISKY_KEYWORDS = /\b(delete|remove|pay|purchase|submit|confirm|checkout|tran
|
|
|
118
142
|
function elementTextRisky(text) {
|
|
119
143
|
return text != null && RISKY_KEYWORDS.test(text);
|
|
120
144
|
}
|
|
121
|
-
function
|
|
145
|
+
function candidateText(selector, candidates) {
|
|
146
|
+
const match = candidates?.find((c) => c.selector === selector);
|
|
147
|
+
return match ? [match.label, match.text, match.placeholder].filter(Boolean).join(" ") || void 0 : void 0;
|
|
148
|
+
}
|
|
149
|
+
function assessRisk(action, candidates) {
|
|
122
150
|
switch (action.type) {
|
|
123
151
|
case "navigate": {
|
|
152
|
+
if (action.url.startsWith("#") || action.url.startsWith("/") || action.url.startsWith("./") || action.url.startsWith("../")) {
|
|
153
|
+
return "safe";
|
|
154
|
+
}
|
|
124
155
|
try {
|
|
125
156
|
const next = new URL(action.url);
|
|
126
157
|
if (!["http:", "https:"].includes(next.protocol)) {
|
|
@@ -131,10 +162,14 @@ function assessRisk(action) {
|
|
|
131
162
|
}
|
|
132
163
|
return "safe";
|
|
133
164
|
}
|
|
134
|
-
case "click":
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
165
|
+
case "click": {
|
|
166
|
+
const text = action.label ?? candidateText(action.selector, candidates) ?? action.selector;
|
|
167
|
+
return elementTextRisky(text) ? "review" : "safe";
|
|
168
|
+
}
|
|
169
|
+
case "type": {
|
|
170
|
+
const text = action.label ?? candidateText(action.selector, candidates) ?? action.selector;
|
|
171
|
+
return elementTextRisky(text) ? "review" : "safe";
|
|
172
|
+
}
|
|
138
173
|
case "focus":
|
|
139
174
|
case "scroll":
|
|
140
175
|
case "wait":
|
|
@@ -185,6 +220,9 @@ async function executeAction(action) {
|
|
|
185
220
|
}
|
|
186
221
|
case "type": {
|
|
187
222
|
const input = mustFind(action.selector);
|
|
223
|
+
if (input.value === action.text) {
|
|
224
|
+
return `Already contains correct value in ${action.selector}`;
|
|
225
|
+
}
|
|
188
226
|
input.focus();
|
|
189
227
|
if (action.clearFirst) {
|
|
190
228
|
input.value = "";
|
|
@@ -288,8 +326,8 @@ function cssPath(element) {
|
|
|
288
326
|
return parts.join(" > ");
|
|
289
327
|
}
|
|
290
328
|
function isVisible(el) {
|
|
291
|
-
if (el.offsetParent === null && el.tagName !== "BODY") return false;
|
|
292
329
|
const style = window.getComputedStyle(el);
|
|
330
|
+
if (el.offsetParent === null && el.tagName !== "BODY" && style.position !== "fixed") return false;
|
|
293
331
|
if (style.display === "none" || style.visibility === "hidden" || style.opacity === "0") return false;
|
|
294
332
|
const rect = el.getBoundingClientRect();
|
|
295
333
|
return rect.width > 0 || rect.height > 0;
|
|
@@ -298,6 +336,14 @@ function isInViewport(el) {
|
|
|
298
336
|
const rect = el.getBoundingClientRect();
|
|
299
337
|
return rect.bottom > 0 && rect.top < window.innerHeight && rect.right > 0 && rect.left < window.innerWidth;
|
|
300
338
|
}
|
|
339
|
+
function isActiveElement(el) {
|
|
340
|
+
if (el.classList.contains("active")) return true;
|
|
341
|
+
if (el.getAttribute("aria-selected") === "true") return true;
|
|
342
|
+
const ariaCurrent = el.getAttribute("aria-current");
|
|
343
|
+
if (ariaCurrent && ariaCurrent !== "false") return true;
|
|
344
|
+
if (el.getAttribute("aria-pressed") === "true") return true;
|
|
345
|
+
return false;
|
|
346
|
+
}
|
|
301
347
|
function getAssociatedLabel(el) {
|
|
302
348
|
if (el.id) {
|
|
303
349
|
const label = document.querySelector(`label[for="${CSS.escape(el.id)}"]`);
|
|
@@ -319,19 +365,22 @@ function getAssociatedLabel(el) {
|
|
|
319
365
|
function collectSnapshot() {
|
|
320
366
|
const allNodes = Array.from(
|
|
321
367
|
document.querySelectorAll(CANDIDATE_SELECTOR)
|
|
322
|
-
).filter(isVisible);
|
|
368
|
+
).filter(isVisible).filter((el) => !el.closest("[data-agent-exclude]"));
|
|
323
369
|
const inView = allNodes.filter(isInViewport);
|
|
324
370
|
const offScreen = allNodes.filter((el) => !isInViewport(el));
|
|
325
371
|
const nodes = [...inView, ...offScreen].slice(0, MAX_CANDIDATES);
|
|
326
372
|
const candidates = nodes.map((node) => {
|
|
327
373
|
const placeholder = node.placeholder?.trim() || node.getAttribute("placeholder")?.trim();
|
|
374
|
+
const controlValue = node instanceof HTMLInputElement || node instanceof HTMLTextAreaElement || node instanceof HTMLSelectElement ? String(node.value ?? "").trim().slice(0, 120) : void 0;
|
|
328
375
|
const associatedLabel = getAssociatedLabel(node);
|
|
329
376
|
return {
|
|
330
377
|
selector: cssPath(node),
|
|
331
378
|
role: node.getAttribute("role") ?? node.tagName.toLowerCase(),
|
|
332
379
|
text: (node.innerText || node.getAttribute("name") || "").trim().slice(0, 120),
|
|
380
|
+
value: controlValue,
|
|
333
381
|
placeholder: placeholder || void 0,
|
|
334
|
-
label: associatedLabel || void 0
|
|
382
|
+
label: associatedLabel || void 0,
|
|
383
|
+
active: isActiveElement(node) || void 0
|
|
335
384
|
};
|
|
336
385
|
});
|
|
337
386
|
const textPreview = document.body.innerText.replace(/\s+/g, " ").trim().slice(0, 1500);
|
|
@@ -410,14 +459,15 @@ function toPlannerResult(raw) {
|
|
|
410
459
|
return { action: raw };
|
|
411
460
|
}
|
|
412
461
|
async function parsePlannerText(raw) {
|
|
413
|
-
const
|
|
414
|
-
|
|
462
|
+
const { parsePlannerResult: parsePlannerResult2, PARSE_FAILURE_PATTERN: PARSE_FAILURE_PATTERN2 } = await Promise.resolve().then(() => (init_parse_action(), parse_action_exports));
|
|
463
|
+
const result = parsePlannerResult2(raw);
|
|
464
|
+
const parseFailed = result.action.type === "done" && PARSE_FAILURE_PATTERN2.test(result.action.reason);
|
|
465
|
+
return { result, parseFailed };
|
|
415
466
|
}
|
|
416
467
|
async function normalizeBridgeResponse(raw) {
|
|
417
468
|
if (typeof raw === "string") {
|
|
418
|
-
const
|
|
419
|
-
|
|
420
|
-
return { result: parsed, parseFailed, rawText: raw };
|
|
469
|
+
const { result, parseFailed } = await parsePlannerText(raw);
|
|
470
|
+
return { result, parseFailed, rawText: raw };
|
|
421
471
|
}
|
|
422
472
|
return { result: toPlannerResult(raw), parseFailed: false };
|
|
423
473
|
}
|
|
@@ -468,7 +518,7 @@ async function runTick(session) {
|
|
|
468
518
|
});
|
|
469
519
|
const { action } = plannerResult;
|
|
470
520
|
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;
|
|
471
|
-
const risk = assessRisk(action);
|
|
521
|
+
const risk = assessRisk(action, snapshot.candidates);
|
|
472
522
|
if (risk === "blocked") {
|
|
473
523
|
return { status: "blocked", action, message: `Blocked action: ${JSON.stringify(action)}`, reflection };
|
|
474
524
|
}
|
package/dist/content.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/shared/parse-action.ts", "../src/shared/safety.ts", "../src/core/executor.ts", "../src/core/observer.ts", "../src/core/planner.ts", "../src/content/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, 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 { 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 { AgentSession, ContentCommand, ContentResult } from \"../shared/contracts\";\nimport { assessRisk } from \"../shared/safety\";\nimport { executeAction } from \"../core/executor\";\nimport { collectSnapshot } from \"../core/observer\";\nimport { planNextAction } from \"../core/planner\";\n\nlet stopped = false;\n\nasync function runTick(session: AgentSession): Promise<ContentResult> {\n const snapshot = collectSnapshot();\n const plannerResult = await planNextAction(session.planner, {\n goal: session.goal,\n snapshot,\n history: session.history,\n lastError: session.lastError,\n memory: session.memory\n });\n\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 (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 try {\n const message = await executeAction(action);\n return { status: \"executed\", action, message, reflection };\n } catch (error) {\n return { status: \"error\", action, message: String(error), reflection };\n }\n}\n\nasync function executePendingAction(session: AgentSession): Promise<ContentResult> {\n if (!session.pendingAction) {\n return { status: \"error\", message: \"No pending action to approve\" };\n }\n\n const message = await executeAction(session.pendingAction);\n return { status: \"executed\", action: session.pendingAction, message };\n}\n\nchrome.runtime.onMessage.addListener((command: ContentCommand, _sender, sendResponse) => {\n if (command.type === \"AGENT_STOP\") {\n stopped = true;\n sendResponse({ status: \"done\", message: \"Stopped by user\" } satisfies ContentResult);\n return true;\n }\n\n if (command.type !== \"AGENT_TICK\") {\n return false;\n }\n\n const session = command.session;\n const exec = session.pendingAction ? executePendingAction(session) : runTick(session);\n\n exec\n .then((result) => {\n if (stopped) {\n sendResponse({ status: \"done\", message: \"Stopped\" } satisfies ContentResult);\n return;\n }\n sendResponse(result);\n })\n .catch((error) => {\n sendResponse({ status: \"error\", message: String(error) } satisfies ContentResult);\n });\n\n return true;\n});\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["input"]
|
|
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, 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 { 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 { AgentSession, ContentCommand, ContentResult } from \"../shared/contracts\";\nimport { assessRisk } from \"../shared/safety\";\nimport { executeAction } from \"../core/executor\";\nimport { collectSnapshot } from \"../core/observer\";\nimport { planNextAction } from \"../core/planner\";\n\nlet stopped = false;\n\nasync function runTick(session: AgentSession): Promise<ContentResult> {\n const snapshot = collectSnapshot();\n const plannerResult = await planNextAction(session.planner, {\n goal: session.goal,\n snapshot,\n history: session.history,\n lastError: session.lastError,\n memory: session.memory\n });\n\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, snapshot.candidates);\n if (risk === \"blocked\") {\n return { status: \"blocked\", action, message: `Blocked action: ${JSON.stringify(action)}`, reflection };\n }\n\n if (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 try {\n const message = await executeAction(action);\n return { status: \"executed\", action, message, reflection };\n } catch (error) {\n return { status: \"error\", action, message: String(error), reflection };\n }\n}\n\nasync function executePendingAction(session: AgentSession): Promise<ContentResult> {\n if (!session.pendingAction) {\n return { status: \"error\", message: \"No pending action to approve\" };\n }\n\n const message = await executeAction(session.pendingAction);\n return { status: \"executed\", action: session.pendingAction, message };\n}\n\nchrome.runtime.onMessage.addListener((command: ContentCommand, _sender, sendResponse) => {\n if (command.type === \"AGENT_STOP\") {\n stopped = true;\n sendResponse({ status: \"done\", message: \"Stopped by user\" } satisfies ContentResult);\n return true;\n }\n\n if (command.type !== \"AGENT_TICK\") {\n return false;\n }\n\n const session = command.session;\n const exec = session.pendingAction ? executePendingAction(session) : runTick(session);\n\n exec\n .then((result) => {\n if (stopped) {\n sendResponse({ status: \"done\", message: \"Stopped\" } satisfies ContentResult);\n return;\n }\n sendResponse(result);\n })\n .catch((error) => {\n sendResponse({ status: \"error\", message: String(error) } satisfies ContentResult);\n });\n\n return true;\n});\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["input", "parsePlannerResult", "PARSE_FAILURE_PATTERN"]
|
|
7
7
|
}
|