
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
Embeddable AI Agent SDK for browsers — let AI operate your web pages via tool-calling
浏览器内嵌 AI Agent SDK:让 AI 通过 tool-calling 操作网页。
核心主张:通过 Prompt + Tools + 路由,快速为网站实现 AI 赋能,并构建前端运行时 AI Skill。AutoPilot 本质上是一个运行在前端浏览器中的 AI Agent。
AutoPilot 的目标不是生成文本,而是在浏览器中完成真实任务:点击、填写、导航、等待、执行脚本,并在每一轮根据最新页面状态持续推进。
它的机制可以概括为三句话:
AutoPilot 的定位是"Web 端原生 Agent 补充层":在当前行业里,大多数 Agent 仍以"后端服务编排 + API 调用"为主,而真正长期驻留在前端浏览器、直接理解并操作真实页面状态的 Agent 仍然稀缺。AutoPilot 关注的正是这块空白能力。
npm install agentpage
core:环境无关引擎(Agent Loop、AI Client、Tool Registry)web:浏览器能力实现(DOM/导航/快照/等待/执行)核心公式:
三层职责:
为什么这个模型对复杂业务有效:
因此它非常适合 DevOps/ERP 等高复杂前端系统:可按路由渐进式接入,不需要一次性重构全站。
对 DevOps / ERP 这类复杂系统尤其关键:
REMAINING 协议跟踪进度,支持协议修复和启发式回退,确保复杂多步任务稳定收敛。select_option value/label/index 三策略。EventTarget.prototype 补丁全局追踪事件绑定,快照中输出 listeners="clk,inp,chg" 信号,帮助 AI 精准识别真实可交互元素,而非猜测。assert 触发独立断言 AI 判定任务完成。三阶段快照设计(初始/动作后/当前)覆盖创建、跳转、状态变更等全场景;断言死循环防护确保不会无限重试。AgentLoopMetrics(轮次、成功率、恢复次数、快照体积、Token 消耗、停机原因 stopReason),可直接接入监控系统。core 零 DOM 依赖,可在 Worker/Extension/Node 复用;web 封装浏览器能力。对于企业前端系统(尤其是 DevOps / ERP),真正决定成败的不是"有没有 Agent",而是是否能在真实路由中稳定收敛。AutoPilot 的价值在于它把落地拆成可持续演进的能力模型,而不是一次性大改造。
在工程实践中,建议围绕三条主线理解和建设:
为什么这种方式能在企业系统里成立:
最终形态不是"在网页里放一个会聊天的助手",而是"在前端运行时形成一套可配置、可执行、可演进的 AI Skill 网络"。
import { WebAgent } from "agentpage";
const agent = new WebAgent({
token: "your-api-key",
provider: "openai", // openai | copilot | anthropic | deepseek | doubao | qwen
model: "gpt-4o",
});
agent.registerTools(); // 注册内置 Web 工具
agent.callbacks = {
onRound: (round) => console.log(`第 ${round + 1} 轮`),
onToolCall: (name, input) => console.log("调用:", name, input),
onToolResult: (name, result) => console.log("结果:", name, result.content),
onText: (text) => console.log("回复:", text),
};
const result = await agent.chat("打开任务弹窗,填写标题和优先级,然后提交");
console.log(result.reply);
console.log(result.metrics); // { roundCount, toolSuccessRate, inputTokens, ... }
const routeSkills: Record<string, { prompt: string; tools?: () => void }> = {
"/tickets": {
prompt: "You are on tickets page. Prioritize filtering and status updates.",
},
"/deploy": {
prompt: "You are on deploy page. Confirm risky actions before release.",
tools: () => agent.registerTool(createDeployTool()),
},
};
function applyRouteSkill(path: string) {
agent.clearCustomTools();
agent.clearSystemPrompts();
const skill = routeSkills[path];
if (!skill) return;
agent.setSystemPrompt(skill.prompt);
skill.tools?.();
}
applyRouteSkill(location.pathname);
┌──────────────────────────────────────────────────────┐
│ WebAgent (web) │
│ ┌──────────┐ ┌──────────────┐ ┌────────────────┐ │
│ │ AI Client│ │ Agent Loop │ │ Web Tools │ │
│ │ (fetch) │ │ (core 循环) │ │ (DOM/导航/等待)│ │
│ └──────────┘ └──────────────┘ └────────────────┘ │
└──────────────────────────────────────────────────────┘
| 层级 | 职责 | 约束 |
|---|---|---|
core | AI 客户端适配、Agent Loop 编排、工具注册分发、系统提示词 | 不依赖 DOM API,可在任意 JS 运行时复用 |
web | WebAgent 入口、5 个内置工具、RefStore 映射、事件追踪、UI 面板 | 依赖浏览器 API,不反向污染 core |
AI 每轮不是"凭记忆猜页面",而是基于最新 DOM 快照选择可执行动作:
输入:当前快照 S + 当前任务 R → 输出:可执行任务批次 T
快照包含:
[combobox]/[slider] 替代冗余 tag+role)#a1b2c)— 仅交互元素携带,非交互元素作为上下文checked/disabled/readonly/val/selected)listeners="clk,inp,chg")— 基于运行时真实绑定collapsed-group 标记、视口裁剪、节点预算控制用户任务被逐轮"吃掉",不一次性硬做完:
总任务: A → B → C
Round 1: 执行 A → REMAINING: B → C
Round 2: 执行 B → REMAINING: C
Round 3: 执行 C → REMAINING: DONE
每轮消息携带:当前剩余任务 + 上轮已执行动作 + 效果检查提示 + 最新快照。
REMAINING: <text> 表示还有剩余,REMAINING: DONE 表示完成focus→fill→focus→fill)click 始终是本轮最后一个动作,执行后强制断轮| 机制 | 触发条件 | 效果 |
|---|---|---|
| 元素未找到恢复 | dom 操作命中失败 | 等待 100ms → 刷新快照 → 返回恢复标记 |
| Not-found 重试对话流 | 本轮存在未找到元素 | 注入失败上下文 + attempt x/y,最多 2 轮 |
| 导航后上下文刷新 | navigate 成功 | 重置 RefStore + 刷新快照 |
| 空转检测 | 连续只读无推进 | 自动终止循环 |
| 重复批次防自转 | 连续两轮相同任务批次 | 直接终止 |
| 协议修复回合 | remaining 未完成却无工具调用 | 注入强约束提示 |
| 轮次稳定等待 | 本轮有 DOM 变化动作 | loading hidden + DOM quiet(200ms/4s) |
| 快照指纹变化检测 | 本轮有 DOM 变更动作且行动后指纹不变 | 注入 Snapshot unchanged 提示,强制模型换目标 |
| 快照变化摘要 | Round 1+ 且前后快照 diff 非空 | 在快照前注入 ## Snapshot Changes 变化行摘要,让 AI 直接看到什么变了 |
| 无效点击拦截与循环检测 | 快照未变时记录无效 click;近 4 轮在 ≤2 个目标间循环 | 拦截重复无效点击;循环检测后将所有循环目标加入拦截集 |
| 附近可点击元素推荐 | 点击被拦截或证实无效 | 从快照中查找目标附近 15 行内有点击信号的元素,按距离推荐 |
| 原始目标锚定 | Round 1+ 每轮 | 注入用户原始任务作为对照组,防止多步执行中偏航 |
| 断言验证(Assertion) | AI 主动调用 assert({}) 工具 | 独立 AI 判定任务完成(三阶段快照对比);全通过则停机,未通过注入进度继续循环 |
| 断言死循环防护 | 连续 2 轮仅调 assert(无其他工具)且都失败 | 自动停机 stopReason = "assertion_loop",避免无限重试 |
| 停机原因可观测 | 每次停机时 | metrics.stopReason 输出枚举值(converged / assertion_passed / assertion_loop / repeated_batch / idle_loop / no_protocol / max_rounds 等) |
每次停机时,metrics.stopReason 会输出精确的停机原因枚举值:
| stopReason | 停机场景 |
|---|---|
converged | 模型返回 REMAINING: DONE 或 remaining 收敛为空 |
assertion_passed | AI 调用 assert 工具且所有任务断言均通过 |
assertion_loop | 连续 2 轮仅调 assert 且都失败(断言死循环防护) |
repeated_batch | 连续相同工具调用批次 ≥ 3 轮(防自转) |
idle_loop | 连续只读轮次触发空转检测 |
no_protocol | 连续多轮有工具调用但无 REMAINING 协议且无有效推进 |
protocol_fix_failed | 协议修复轮失败(无工具调用 + remaining 未收敛) |
max_rounds | 达到 maxRounds 上限 |
dry_run | dry-run 模式,仅展示不执行 |
assert 是内置工具,AI 认为任务完成时主动调用 assert({}) 触发验证:
AI 执行动作 → 认为完成 → 调用 assert({})
↓
拍取动作后快照(捕获瞬态反馈)
↓
等待页面稳定 → 清除 hover → 刷新快照
↓
独立断言 AI(专用 Prompt,无 tools)基于三阶段快照判定
↓
全部通过 → stopReason: "assertion_passed"
部分失败 → 注入 Assertion Progress → 继续循环
断言 AI 同时接收三份快照,覆盖不同阶段的页面状态:
| 快照 | 拍取时机 | 用途 |
|---|---|---|
| Initial | 任务开始前 | 基线对比:判断创建/修改/删除等长任务是否完成 |
| Post-Action | 工具执行完成后、稳定等待前 | 捕获瞬态反馈:成功提示、确认弹窗等跳转后消失的信息 |
| Current | 稳定等待 + hover 清除后 | 最终状态:确认页面实际结果 |
这个设计解决了真实 B 端场景中的关键问题:
连续 2 轮执行 AI 仅调用 assert(无其他工具)且都失败时,自动停机 stopReason = "assertion_loop",避免无限重试。
无自定义断言时,以用户原始消息作为整体断言依据。
const result = await agent.chat("关闭开关,满意度五星,标签选灰度", {
assertionConfig: {
taskAssertions: [
{ task: "关闭开关", description: "开关组件不应有 is-checked class" },
{ task: "满意度五星", description: "满意度 slider 的 5 个 star 均应有 is-active class" },
{ task: "标签选灰度", description: "灰度 checkbox 应有 checked 状态" },
],
},
});
console.log(result.assertionResult);
// { allPassed: true, total: 3, passed: 3, failed: 0, details: [...] }
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
client | AIClient | - | 自定义 AI 客户端实例;传入后忽略 token/provider/model/baseURL |
token | string | "" | API Token(GitHub PAT / OpenAI Key / Anthropic Key 等) |
provider | string | "copilot" | AI 服务商(见下方 Provider 表) |
model | string | "gpt-4o" | 模型名称(需与 provider 匹配) |
baseURL | string | - | 自定义 API 端点(代理/私有部署) |
stream | boolean | true | 是否启用 SSE 流式输出 |
requestTimeoutMs | number | 45000 | 单次 AI 请求超时(毫秒) |
dryRun | boolean | false | 干运行模式:输出工具计划但不执行 |
systemPrompt | string | Record<string, string> | 内置 | 自定义 Prompt;支持单条或 key-value 多条注册 |
maxRounds | number | 40 | 单次 chat 最大循环轮次 |
memory | boolean | false | 是否开启多轮对话记忆(跨 chat 保留历史) |
autoSnapshot | boolean | true | chat 前自动生成首轮快照 |
snapshotOptions | SnapshotOptions | {} | 快照参数(深度、裁剪、节点上限等) |
roundStabilityWait | RoundStabilityWaitOptions | { enabled: true } | 轮次后稳定等待配置 |
panel | boolean | PanelOptions | - | 内置 UI 面板配置(见下方 PanelOptions 表) |
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
container | HTMLElement | document.body | 面板挂载容器 |
mount | boolean | true | 构造时是否自动挂载到 DOM |
enableMask | boolean | true | Agent 运行时是否显示操作遮罩 |
maskOpacity | number | 0.15 | 遮罩背景透明度(0–1,0 全透明,1 纯白) |
expanded | boolean | false | 面板初始展开状态 |
title | string | "AutoPilot" | 面板标题 |
placeholder | string | "输入要执行的网页操作..." | 输入框占位文本 |
maskText | string | "AutoPilot 正在操作页面" | 遮罩提示文本 |
emptyText | string | "发送一条消息,AI 将帮你操作页面" | 空状态提示文本 |
| Provider | 默认端点 | 推荐模型 |
|---|---|---|
copilot | GitHub Copilot API | gpt-4o |
openai | https://api.openai.com/v1 | gpt-4o / gpt-4o-mini |
anthropic | https://api.anthropic.com | claude-sonnet-4-20250514 |
deepseek | https://api.deepseek.com | deepseek-chat |
doubao | https://ark.cn-beijing.volces.com/api/v3 | doubao-1.5-pro-32k |
qwen | https://dashscope.aliyuncs.com/compatible-mode/v1 | qwen-plus |
minimax | https://api.minimaxi.com/v1 | MiniMax-M2.5 |
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
maxDepth | number | 12 | DOM 最大遍历深度 |
viewportOnly | boolean | false | 仅保留视口内元素 |
pruneLayout | boolean | true | 折叠无意义布局容器,子节点提升 |
maxNodes | number | 500 | 快照最大节点数 |
maxChildren | number | 30 | 每个父节点最大子元素数 |
maxTextLength | number | 40 | 文本截断长度 |
listenerEvents | string[] | 9 种常用事件 | 快照输出的 listener 事件白名单 |
classNameFilter | string[] | false | 内置 UI 框架过滤 | class 名过滤正则列表,匹配即剔除;false 禁用 |
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
enabled | boolean | true | 是否启用 |
timeoutMs | number | 4000 | 总超时 |
quietMs | number | 200 | DOM 静默窗口 |
loadingSelectors | string[] | AntD/ElementPlus/BK/TDesign 等 | 追加合并,不覆盖默认 |
6 个内置工具通过 agent.registerTools() 一次注册。
| 动作 | 说明 | 关键参数 |
|---|---|---|
click | 点击(完整 pointer/mouse 事件链) | selector, clickCount |
fill | 清空后填写 | selector, value |
type | 逐字追加输入 | selector, value |
press | 按键(支持 Control+a 组合键) | selector, key |
select_option | 选择下拉选项(value/label/index 三策略) | selector, value/label/index |
check / uncheck | 勾选/取消 checkbox | selector |
clear | 清空输入框 | selector |
focus / hover | 聚焦/悬停 | selector |
get_text / get_attr | 读取文本/属性 | selector |
set_attr / add_class / remove_class | 修改属性/类名 | selector, value |
Playwright 风格增强:
ifNeeded → end → center → start,解决 sticky 遮挡value setter,text 类走 selectAll + 原生写入pointermove→pointerdown→mousedown→focus→pointerup→mouseup→click| 动作 | 说明 |
|---|---|
goto | 跳转到指定 URL |
back / forward | 浏览器后退/前进 |
reload | 刷新页面 |
scroll | 滚动到指定元素或坐标 |
| 动作 | 说明 | state |
|---|---|---|
wait_for_selector | 等待选择器达到状态 | attached/visible/hidden/detached |
wait_for_hidden | 等待元素隐藏 | - |
wait_for_text | 等待页面出现文本 | - |
wait_for_stable | 等待 DOM 静默 | - |
双通道检测:轮询(80ms)+ MutationObserver,确保快速响应又不遗漏。
get_url / get_title / get_selection / get_viewport / snapshot / query_all
page_info.snapshot是框架内部动作;快照每轮自动刷新并注入给模型,模型无需主动调用。
执行页面上下文 JavaScript 表达式或语句块。兜底工具,适用于其他工具无法覆盖的场景。
AI 认为任务完成时主动调用 assert({}),框架发起独立 AI 判定(专用 Prompt、无 tools、不继承 system prompt),基于三阶段快照对比验证任务是否真正完成。
ChatOptions.assertionConfig.taskAssertions 传入细粒度子任务断言stopReason = "assertion_passed",循环终止## Assertion Progress 区块,AI 聚焦修复后再次触发断言pointerleave/mouseleave 清除瞬态视觉状态,确保快照反映持久状态// 方式 1:初始化单条
const agent = new WebAgent({
systemPrompt: "Only operate deploy-related UI. Confirm before release.",
});
// 方式 2:key-value 多条
const agent = new WebAgent({
systemPrompt: {
safety: "Never delete data without confirmation.",
deploy: "Confirm risky actions before triggering release.",
},
});
// 方式 3:运行时维护
agent.setSystemPrompt("tickets", "Prioritize filtering and status updates.");
agent.removeSystemPrompt("tickets");
agent.keepOnlySystemPrompt("deploy");
agent.clearSystemPrompts();
已注册 Prompt 作为扩展段追加到内置系统提示词之后。内置 Prompt 包含:快照优先决策、REMAINING 协议、批量执行规则、Effect check、事件信号优先级、禁止 page_info 空转等核心约束。
import { Type } from "@sinclair/typebox";
agent.registerTool({
name: "create_ticket",
description: "Create a new ticket in the system",
schema: Type.Object({
title: Type.String({ description: "Ticket title" }),
priority: Type.String({ enum: ["high", "medium", "low"] }),
}),
async execute(params) {
await api.createTicket(params);
return { content: `Ticket created: ${params.title}` };
},
});
工具管理:registerTool() / removeTool() / hasTool() / getToolNames() / clearCustomTools() / getTools()
内置工具(dom/navigate/page_info/wait/evaluate/assert)受保护,不允许删除。
import { BaseAIClient } from "agentpage";
const agent = new WebAgent({
client: new BaseAIClient({
chatHandler: async ({ url, method, headers, body }) => {
const res = await fetch("/api/ai-proxy", { method: "POST", body });
return res;
},
}),
});
也可以实现 AIClient 接口直接传入:
type AIClient = {
chat(params: {
systemPrompt: string;
messages: AIMessage[];
tools?: ToolDefinition[];
}): Promise<{ text?: string; toolCalls?: AIToolCall[]; usage?: { inputTokens: number; outputTokens: number } }>;
};
agent.callbacks = {
onRound: (round) => console.log(`── Round ${round + 1} ──`),
onText: (text) => ui.appendText(text),
onToolCall: (name, input) => ui.showLoading(name),
onToolResult: (name, result) => ui.showResult(name, result.content),
onSnapshot: (snapshot) => console.log(`快照: ${snapshot.length} chars`),
onMetrics: (metrics) => analytics.track("chat_complete", metrics),
};
| 字段 | 说明 |
|---|---|
roundCount | 实际执行轮次 |
totalToolCalls / successfulToolCalls / failedToolCalls | 工具调用计数 |
toolSuccessRate | 成功率(0-1) |
recoveryCount | 元素恢复触发次数 |
redundantInterceptCount | 冗余拦截次数 |
snapshotReadCount / latestSnapshotSize / avgSnapshotSize / maxSnapshotSize | 快照统计 |
inputTokens / outputTokens | Token 消耗 |
stopReason | 停机原因枚举(converged / assertion_passed / assertion_loop / repeated_batch / idle_loop / no_protocol / protocol_fix_failed / max_rounds / dry_run) |
| 字段 | 类型 | 说明 |
|---|---|---|
reply | string | AI 最终回复 |
toolCalls | Array<{ name, input, result }> | 完整工具调用轨迹 |
messages | AIMessage[] | 完整对话消息(可用于 memory) |
metrics | AgentLoopMetrics | 运行指标 |
assertionResult | AssertionResult | 断言结果(仅在 AI 触发 assert 时存在) |
chat(task) 触发
│
├─ 创建 RefStore,生成首轮快照 S₀
│
└─ 进入 executeAgentLoop 循环
│
├─ 1. Ensure Snapshot — 确保有最新快照
├─ 2. Build Messages — remaining + 上轮轨迹 + 效果检查 + 快照
├─ 3. Call AI — 拿到 text + toolCalls + REMAINING
├─ 4. Execute Tools — 逐个分发,应用保护机制
├─ 5. Reduce Remaining — 推进任务(协议优先,启发式回退)
├─ 6. Guard — 防空转/防自转/协议修复判定
└─ 7. Refresh Snapshot → 下一轮
│
└─ 停机 → 返回 AgentLoopResult
src/
├── core/ # 环境无关引擎
│ ├── index.ts # Core 入口
│ ├── types.ts # 共享类型
│ ├── system-prompt.ts # 系统提示词构建
│ ├── tool-registry.ts # 工具注册表
│ ├── tool-params.ts # 参数辅助
│ ├── snapshot.ts # 快照聚合出口(兼容)
│ ├── snapshot-engine.ts # 兼容转发层(-> agent-loop/snapshot/engine)
│ ├── messaging.ts # 消息桥接实现
│ ├── event-listener-tracker.ts # 事件追踪实现
│ ├── agent-loop/ # Agent 循环
│ │ ├── index.ts # 主流程编排
│ │ ├── messages.ts # 紧凑消息构建
│ │ ├── snapshot.ts # 兼容转发层(-> snapshot/lifecycle)
│ │ ├── snapshot/ # 快照子模块
│ │ │ ├── index.ts
│ │ │ ├── lifecycle.ts # 快照读取/包裹/去重
│ │ │ └── engine.ts # DOM 快照序列化引擎
│ │ ├── recovery.ts # 兼容转发层(-> recovery/index)
│ │ ├── recovery/ # 恢复与拦截子模块
│ │ │ └── index.ts
│ │ ├── assertion/ # 断言子模块
│ │ │ ├── types.ts # 断言类型定义
│ │ │ ├── prompt.ts # 断言专用 Prompt
│ │ │ └── index.ts # 断言引擎
│ │ ├── helpers.ts # 纯函数工具
│ │ ├── constants.ts # 默认常量
│ │ ├── types.ts # 循环类型
│ │ └── LOOP_MECHANISM.md # 机制权威说明
│ └── ai-client/ # AI 客户端
│ ├── index.ts # Provider 路由
│ ├── openai.ts # OpenAI/Copilot
│ ├── anthropic.ts # Anthropic
│ ├── deepseek.ts # DeepSeek
│ ├── doubao.ts # 豆包 (Ark)
│ ├── qwen.ts # 通义千问
│ ├── custom.ts # BaseAIClient 基类
│ ├── sse.ts # SSE 解析器
│ └── constants.ts # 端点与校验
└── web/ # 浏览器实现
├── index.ts # WebAgent 入口
├── ref-store.ts # #hashID → Element 映射
├── event-listener-tracker.ts # 兼容转发层(-> core)
├── messaging.ts # 兼容转发层(-> core)
├── snapshot.ts # 兼容转发层(-> core)
├── snapshot-engine.ts # 兼容转发层(-> core)
├── ui/ # 内置 UI 面板
└── tools/ # 工具实现
├── dom-tool.ts
├── navigate-tool.ts
├── page-info-tool.ts
├── wait-tool.ts
└── evaluate-tool.ts
pnpm install # 安装依赖
pnpm check # 类型检查 + Lint
pnpm test # 运行测试
pnpm demo # 启动 Demo
pnpm build # 构建
MIT
FAQs
Embeddable AI Agent SDK for browsers — let AI operate your web pages via tool-calling
The npm package agentpage receives a total of 114 weekly downloads. As such, agentpage popularity was classified as not popular.
We found that agentpage demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.