agentpage 0.0.19 → 0.0.21
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/README.md +1 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +82 -8
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/core/tool-registry.ts","../src/core/types.ts","../src/core/agent-loop/types.ts","../src/web/ref-store.ts","../src/web/tools/page-info-tool.ts","../src/web/tools/dom-tool.ts","../src/web/tools/navigate-tool.ts","../src/web/tools/wait-tool.ts","../src/web/tools/evaluate-tool.ts","../src/web/messaging.ts","../src/web/index.ts"],"mappings":";;;;;;KA0BY,cAAA;EAuBV,qCArBA,OAAA,WAAkB,MAAA,mBAqBR;EAnBV,OAAA,GAAU,MAAA;AAAA;;;;;;ACfZ;;;KD0BY,cAAA;ECxBV,4CD0BA,IAAA,UCtBA;EDwBA,WAAA,UCxBK;ED0BL,MAAA,EAAQ,OAAA,ECpBW;EDsBnB,OAAA,GAAU,MAAA,EAAQ,MAAA,sBAA4B,OAAA,CAAQ,cAAA;AAAA;;;;KClC5C,UAAA;ED0BA,0BCxBV,EAAA;EAEA,IAAA,UD8BkB;EC5BlB,KAAA;AAAA;;KAMU,SAAA;EACV,IAAA,4CDiBA;ECfA,OAAA,WAAkB,KAAA;IAAQ,UAAA;IAAoB,MAAA;EAAA,IDmBpC;ECjBV,SAAA,GAAY,UAAA;AAAA;;KAMF,cAAA;iBAEV,IAAA;EAEA,SAAA,GAAY,UAAA,IA3BQ;EA6BpB,KAAA;IAAU,WAAA;IAAqB,YAAA;EAAA;AAAA;;;AAjBjC;;;KA2BY,QAAA;EACV,IAAA,CAAK,MAAA;IACH,YAAA;IACA,QAAA,EAAU,SAAA;IACV,KAAA,GAAQ,cAAA;EAAA,IACN,OAAA,CAAQ,cAAA;AAAA;;;KClDF,gBAAA;EACV,UAAA;EACA,cAAA;EACA,mBAAA;EACA,eAAA;EACA,eAAA;EACA,aAAA;EACA,uBAAA;EACA,iBAAA;EACA,kBAAA;EACA,eAAA;EACA,eAAA;EACA,WAAA;EACA,YAAA;AAAA;;KAMU,kBAAA;EFmBF,mBEjBR,MAAA,IAAU,IAAA,mBFmBQ;EEjBlB,UAAA,IAAc,IAAA,UAAc,KAAA,oBFiBkB;EEf9C,YAAA,IAAgB,IAAA,UAAc,MAAA,EAAQ,cAAA,WFe8B;EEbpE,OAAA,IAAW,KAAA;;;;ADrBb;;;;;EC8BE,wBAAA,IAA4B,MAAA,oBDxB5B;EC0BA,SAAA,IAAa,OAAA,EAAS,gBAAA;AAAA;AAAA,KA0BZ,eAAA;ED7BA,iBC+BV,KAAA,UD/B2C;ECiC3C,SAAA,EAAW,KAAA;IAAQ,IAAA;IAAc,KAAA;IAAgB,MAAA,EAAQ,cAAA;EAAA,IDnB/C;ECqBV,QAAA,EAAU,SAAA,IDpBN;ECsBJ,OAAA,EAAS,gBAAA;AAAA;;;;;;AFvDX;;;;;;;;;;AAeA;;;;;;;;;;;;;;cGAa,QAAA;EAAA,QACH,GAAA;EHOsC;EAAA,QGLtC,MAAA;EHK4D;;;;cGCxD,GAAA;EFnCF;;;;;;;EE8CV,GAAA,CAAI,EAAA,EAAI,OAAA,EAAS,IAAA;EFxCZ;AAMP;;;EEkDE,GAAA,CAAI,EAAA,WAAa,OAAA;EFjDjB;EEsDA,GAAA,CAAI,EAAA;EFpDc;EEyDlB,KAAA,CAAA;EFzD8C;;;;;AAQhD;;;EE6DE,KAAA,CAAM,GAAA;EF3DN;EAAA,IEmEI,IAAA,CAAA;AAAA;;;;KCvFM,eAAA;EJMc,mBIJxB,QAAA;EJQgB;;;;;EIFhB,YAAA;EJEgB;AAWlB;;;;EIPE,WAAA;EJesD;;;;;EITtD,QAAA,GAAW,QAAA,EJOX;EILA,QAAA,WJOA;EILA,WAAA,WJKU;EIHV,aAAA;AAAA;;;;;;AH/BF;;;;;;;;;AAYA;;;;;;iBG0CgB,gBAAA,CACd,IAAA,GAAM,OAAA,EACN,OAAA,GAAS,eAAA;AAAA,
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/core/tool-registry.ts","../src/core/types.ts","../src/core/agent-loop/types.ts","../src/web/ref-store.ts","../src/web/tools/page-info-tool.ts","../src/web/tools/dom-tool.ts","../src/web/tools/navigate-tool.ts","../src/web/tools/wait-tool.ts","../src/web/tools/evaluate-tool.ts","../src/web/messaging.ts","../src/web/index.ts"],"mappings":"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"}
|
package/dist/index.mjs
CHANGED
|
@@ -90,7 +90,8 @@ function hasToolError(result) {
|
|
|
90
90
|
* 压缩/剪枝是怎么做的(中)/ How compression & pruning works in practice (EN):
|
|
91
91
|
* - `viewportOnly=true` 时:仅保留与视口相交元素(根层容器保留),完全视口外元素跳过。
|
|
92
92
|
* - `pruneLayout=true` 时:无 id/无语义/无交互/无直接文本的布局容器会被“折叠”,
|
|
93
|
-
*
|
|
93
|
+
* 子节点直接提升输出,减少无意义层级;当同一折叠容器提升出多个相邻节点时,
|
|
94
|
+
* 快照会用括号分组块标记其关联来源(collapsed-group)。
|
|
94
95
|
* - `maxNodes`:全局节点预算,超限后停止继续遍历并追加 truncation 提示。
|
|
95
96
|
* - `maxChildren`:每个父节点只保留前 N 个子元素,其余用 `... (n children omitted)` 汇总。
|
|
96
97
|
* - `maxTextLength`:节点文本按长度截断,避免长段文案占满上下文。
|
|
@@ -1368,9 +1369,16 @@ function buildSystemPrompt(params = {}) {
|
|
|
1368
1369
|
" Output: new remaining task after removing this-round actions.",
|
|
1369
1370
|
"- Use only visible targets from snapshot. Use #hashID as selector. Do not guess CSS selectors.",
|
|
1370
1371
|
"- Batch independent visible actions in one round. Do not split one form into many rounds unnecessarily.",
|
|
1372
|
+
"- Strict input order (MANDATORY): before every fill/type/select_option, click or focus the SAME target immediately in the SAME round.",
|
|
1373
|
+
"- Multi-field rule (MANDATORY): execute alternating pairs in one batch: focus/click field A -> fill/type A -> focus/click field B -> fill/type B.",
|
|
1374
|
+
"- Do NOT run focus-only batches (e.g., focus A -> focus B). Each focused input/select target must be followed by its input/select action right away.",
|
|
1375
|
+
"- Fixed sequence examples: dom.focus(#name) -> dom.fill(#name, \"new-name\") -> dom.focus(#desc) -> dom.fill(#desc, \"new-desc\"); dom.click(#select) -> dom.select_option(#select, ...).",
|
|
1376
|
+
"- For check/uncheck, target the real input control (checkbox/radio), not nearby text/container nodes.",
|
|
1377
|
+
"- Form batch rule: for one visible form, complete all independent fields in one round; do not fill one field then verify repeatedly.",
|
|
1371
1378
|
"- If an action will change DOM (open modal, navigate), stop after that action batch and continue next round with new snapshot.",
|
|
1372
1379
|
"- Do NOT call page_info (snapshot/query/get_url/get_title). Snapshot is already provided every round.",
|
|
1373
1380
|
"- For dropdown/select, use dom action=select_option (or fill on select).",
|
|
1381
|
+
"- Verification whitelist: do NOT use get_text/get_attr to verify input/select values unless the user explicitly asks for verification.",
|
|
1374
1382
|
"- Do NOT interact with AutoPilot UI unless user explicitly asks.",
|
|
1375
1383
|
"",
|
|
1376
1384
|
"## Output Contract",
|
|
@@ -1599,6 +1607,53 @@ function isEditableElement(el) {
|
|
|
1599
1607
|
if (el instanceof HTMLSelectElement) return true;
|
|
1600
1608
|
return el instanceof HTMLElement && el.isContentEditable;
|
|
1601
1609
|
}
|
|
1610
|
+
function isCheckableInput(el) {
|
|
1611
|
+
return el instanceof HTMLInputElement && (el.type === "checkbox" || el.type === "radio");
|
|
1612
|
+
}
|
|
1613
|
+
function findCheckableIn(el) {
|
|
1614
|
+
if (!el) return null;
|
|
1615
|
+
const found = el.querySelector("input[type=\"checkbox\"], input[type=\"radio\"]");
|
|
1616
|
+
return isCheckableInput(found) ? found : null;
|
|
1617
|
+
}
|
|
1618
|
+
/**
|
|
1619
|
+
* 归一化 check/uncheck 目标:
|
|
1620
|
+
* 允许模型命中文本容器/label/div,再回溯到关联 checkbox/radio,
|
|
1621
|
+
* 以降低快照剪枝导致的“命中语义节点而非真实控件”失败率。
|
|
1622
|
+
*/
|
|
1623
|
+
function resolveCheckableTarget(el) {
|
|
1624
|
+
if (isCheckableInput(el)) return el;
|
|
1625
|
+
if (el instanceof HTMLLabelElement) {
|
|
1626
|
+
const byLabel = findCheckableIn(el);
|
|
1627
|
+
if (byLabel) return byLabel;
|
|
1628
|
+
const htmlFor = el.htmlFor?.trim();
|
|
1629
|
+
if (htmlFor) {
|
|
1630
|
+
const byFor = document.getElementById(htmlFor);
|
|
1631
|
+
if (isCheckableInput(byFor)) return byFor;
|
|
1632
|
+
}
|
|
1633
|
+
}
|
|
1634
|
+
if (el instanceof HTMLElement) {
|
|
1635
|
+
const ownerLabel = el.closest("label");
|
|
1636
|
+
if (ownerLabel) {
|
|
1637
|
+
const byOwnerLabel = findCheckableIn(ownerLabel);
|
|
1638
|
+
if (byOwnerLabel) return byOwnerLabel;
|
|
1639
|
+
const htmlFor = ownerLabel.htmlFor?.trim();
|
|
1640
|
+
if (htmlFor) {
|
|
1641
|
+
const byFor = document.getElementById(htmlFor);
|
|
1642
|
+
if (isCheckableInput(byFor)) return byFor;
|
|
1643
|
+
}
|
|
1644
|
+
}
|
|
1645
|
+
const inSelf = findCheckableIn(el);
|
|
1646
|
+
if (inSelf) return inSelf;
|
|
1647
|
+
const prev = el.previousElementSibling;
|
|
1648
|
+
if (isCheckableInput(prev)) return prev;
|
|
1649
|
+
const next = el.nextElementSibling;
|
|
1650
|
+
if (isCheckableInput(next)) return next;
|
|
1651
|
+
const parent = el.parentElement;
|
|
1652
|
+
const inParent = findCheckableIn(parent);
|
|
1653
|
+
if (inParent) return inParent;
|
|
1654
|
+
}
|
|
1655
|
+
return null;
|
|
1656
|
+
}
|
|
1602
1657
|
function ensureActionable(el, action, selector) {
|
|
1603
1658
|
if (!el.isConnected) return {
|
|
1604
1659
|
content: `"${selector}" 元素已脱离文档,无法执行 ${action}`,
|
|
@@ -1676,14 +1731,17 @@ function createDomTool() {
|
|
|
1676
1731
|
description: [
|
|
1677
1732
|
"Perform DOM operations on the current page.",
|
|
1678
1733
|
"Actions: click, fill, select_option, clear, check, uncheck, type, focus, hover, press, get_text, get_attr, set_attr, add_class, remove_class.",
|
|
1734
|
+
"Input/Select rule: before each fill/type/select_option, click or focus the same target immediately in the same round.",
|
|
1735
|
+
"For multiple fields, use alternating pairs in one batch: focus/click A -> fill/type A -> focus/click B -> fill/type B.",
|
|
1736
|
+
"Do not send focus-only batches for editable fields.",
|
|
1679
1737
|
"Use the hash ID from DOM snapshot (e.g. #a1b2c) as selector."
|
|
1680
1738
|
].join(" "),
|
|
1681
1739
|
schema: Type.Object({
|
|
1682
|
-
action: Type.String({ description: "DOM action: click | fill | select_option | clear | check | uncheck | type | focus | hover | press | get_text | get_attr | set_attr | add_class | remove_class" }),
|
|
1740
|
+
action: Type.String({ description: "DOM action: click | fill | select_option | clear | check | uncheck | type | focus | hover | press | get_text | get_attr | set_attr | add_class | remove_class. For fill/type/select_option, perform click/focus on same target immediately before it." }),
|
|
1683
1741
|
selector: Type.String({ description: "Element ref ID from snapshot (e.g. #r0, #r5) or CSS selector" }),
|
|
1684
|
-
value: Type.Optional(Type.String({ description: "Value for fill/type/set_attr actions" })),
|
|
1742
|
+
value: Type.Optional(Type.String({ description: "Value for fill/type/set_attr actions. For fill/type, run after click/focus on same target in the same round." })),
|
|
1685
1743
|
key: Type.Optional(Type.String({ description: "Key name for press action (e.g. Enter, Escape, Tab, ArrowDown, ArrowUp, Backspace, Delete, Space)" })),
|
|
1686
|
-
label: Type.Optional(Type.String({ description: "Label text for select_option action (fallback when value is not provided)" })),
|
|
1744
|
+
label: Type.Optional(Type.String({ description: "Label text for select_option action (fallback when value is not provided). Run select_option after click/focus on same target in the same round." })),
|
|
1687
1745
|
index: Type.Optional(Type.Number({ description: "0-based option index for select_option action" })),
|
|
1688
1746
|
attribute: Type.Optional(Type.String({ description: "Attribute name for get_attr/set_attr actions" })),
|
|
1689
1747
|
className: Type.Optional(Type.String({ description: "CSS class name for add_class/remove_class" })),
|
|
@@ -1734,6 +1792,10 @@ function createDomTool() {
|
|
|
1734
1792
|
};
|
|
1735
1793
|
el = elOrError;
|
|
1736
1794
|
}
|
|
1795
|
+
if (action === "check" || action === "uncheck") {
|
|
1796
|
+
const resolvedCheckable = resolveCheckableTarget(el);
|
|
1797
|
+
if (resolvedCheckable) el = resolvedCheckable;
|
|
1798
|
+
}
|
|
1737
1799
|
try {
|
|
1738
1800
|
if (!force) {
|
|
1739
1801
|
const checkResult = ensureActionable(el, action, selector);
|
|
@@ -2251,13 +2313,18 @@ function generateSnapshot(root = document.body, options = {}) {
|
|
|
2251
2313
|
const orderedChildren = [...interactiveChildren, ...nonInteractiveChildren];
|
|
2252
2314
|
const selectedChildren = orderedChildren.slice(0, maxChildren);
|
|
2253
2315
|
const omittedChildren = orderedChildren.length - selectedChildren.length;
|
|
2254
|
-
const
|
|
2316
|
+
const childBlocks = [];
|
|
2255
2317
|
for (let i = 0; i < selectedChildren.length; i++) {
|
|
2256
2318
|
const childResult = walk(selectedChildren[i], depth, currentPath);
|
|
2257
|
-
if (childResult)
|
|
2319
|
+
if (childResult) childBlocks.push(childResult);
|
|
2258
2320
|
}
|
|
2259
|
-
if (
|
|
2260
|
-
return
|
|
2321
|
+
if (childBlocks.length === 0 && omittedChildren <= 0) return "";
|
|
2322
|
+
if (!(childBlocks.length >= 2 || omittedChildren > 0)) return childBlocks.join("\n");
|
|
2323
|
+
const groupLines = [`${" ".repeat(depth)}([${tag}] collapsed-group`];
|
|
2324
|
+
for (const block of childBlocks) groupLines.push(indentMultiline(block, 1));
|
|
2325
|
+
if (omittedChildren > 0) groupLines.push(`${" ".repeat(depth + 1)}... (${omittedChildren} children omitted)`);
|
|
2326
|
+
groupLines.push(`${" ".repeat(depth)})`);
|
|
2327
|
+
return groupLines.join("\n");
|
|
2261
2328
|
}
|
|
2262
2329
|
let line = `${indent}[${tag}]`;
|
|
2263
2330
|
if (directText) line += ` "${directText.slice(0, maxTextLength)}"`;
|
|
@@ -2308,6 +2375,13 @@ function queryAllElements(selector, limit = 20) {
|
|
|
2308
2375
|
return `选择器语法错误: ${selector}`;
|
|
2309
2376
|
}
|
|
2310
2377
|
}
|
|
2378
|
+
/**
|
|
2379
|
+
* 多行文本块缩进(中)/ Indent each line of a multiline block (EN).
|
|
2380
|
+
*/
|
|
2381
|
+
function indentMultiline(block, indentLevel) {
|
|
2382
|
+
const prefix = " ".repeat(indentLevel);
|
|
2383
|
+
return block.split("\n").map((line) => `${prefix}${line}`).join("\n");
|
|
2384
|
+
}
|
|
2311
2385
|
function createPageInfoTool() {
|
|
2312
2386
|
return {
|
|
2313
2387
|
name: "page_info",
|