智页网页智能体

智页是一款运行在浏览器内的网页智能体,用户通过自然语言即可读取、提取、修改当前网页,并具备供应商、模型、环境、会话的完整管理链路与 SubAgent 派发能力,适用于网页自动化、信息提取与浏览器内智能辅助等场景。

  • by lhstack
  • JavaScript
  • 本地部署
  • 1 星标
  • 更新于
在 GitHub 查看 lhstack/SmartPageAgent

使用说明

# 智页(SmartPage Agent)

浏览器内运行的网页智能体。用自然语言读取、提取、修改当前网页,并具备完整的「供应商 → 模型 → 环境 → 会话」管理链路;SubAgent 由环境授权后在对话中被派发。

本版本按 awake-claw 的分层架构与对话交互 重构:原先 6000 余行的单体 background.js 拆分为 infrastructure / antiseptic / application / frontend 四层,管理界面迁移为 Vue 3 + Element Plus。

快速开始

npm install
npm run build          # 产出 dist/

加载扩展:

  1. 打开 chrome://extensions
  2. 开启「开发者模式」
  3. 「加载已解压的扩展程序」→ 选择本仓库的 dist/ 目录
  4. 点击扩展图标打开弹窗,或点齿轮进入控制台(options.html)

首次使用顺序:供应商 → 模型 → 环境 → 新建会话。对话不依赖 Agent:新建会话时直接选环境、供应商、模型与提示词,之后在右侧「模型参数」面板随时调整(自动保存到会话快照)。

分层结构

src/
├─ background/                 # MV3 service worker 入口:消息路由 + 流式对话端口
├─ application/
│   └─ api/router.js           # REST 风格路由(/api/providers、/api/agents …)
├─ antiseptic/                 # 业务编排层(对应 awake-claw 同名层)
│   ├─ provider_business.js    # 供应商(含凭据脱敏、连通性测试)
│   ├─ model_business.js       # 模型(含供应商联表)
│   ├─ agent_business.js       # SubAgent(能力求交、复制、就绪判定)
│   ├─ mcp_business.js         # MCP 服务(含请求头脱敏、工具 schema 查看)
│   ├─ skill_business.js       # 技能(SKILL.md / 资源文件)
│   ├─ environment_business.js # 环境(人格/画像/记忆、资源开关、SubAgent 授权、提示词预览)
│   ├─ session_business.js     # 会话、模型快照与事件时间线
│   ├─ chat_business.js        # 回合执行、重试、停止、并发互斥
│   └─ tool_business.js        # 工具清单与分组设置
├─ infrastructure/
│   ├─ repository/             # IndexedDB 存储,表结构对齐 awake-claw SQLite
│   ├─ model/
│   │   ├─ http.js             # SSE 读取、URL 拼接
│   │   └─ model_params.js     # 协议字段表、默认值、执行参数(前后端共用)
│   ├─ model_provider/         # OpenAI 兼容 / Anthropic 两种协议适配
│   └─ runtime/
│       ├─ tool_loop.js        # 模型 + 工具循环(主会话与 SubAgent 共用)
│       ├─ agent_executor.js   # 会话回合编排:快照解析、资源解析、事件落库
│       ├─ subagent_runtime.js # SubAgent 派发:独立提示、只读/可操作、嵌套事件
│       ├─ prompt_builder.js   # 系统提示组装
│       ├─ mcp_runtime.js      # Streamable HTTP / SSE / HTTP 网关
│       └─ tools/              # 工具注册表:页面 / 标签页 / 脚本 / 技能 / SubAgent
└─ frontend/
    ├─ popup/                  # 扩展弹窗(H5 版对话:顶部工具条 + 会话抽屉 + 事件线)
    ├─ shared/timeline.js      # 事件 → 轮次/块的共用解析(桌面与 H5 同一套语义)
    └─ options/                # 控制台:对话、环境、SubAgent、提示词、模型、MCP、技能、工具、设置

数据模型

IndexedDB 库名 smartpage_agent,objectStore 与 awake-claw 的表一一对应:

表 说明
providers 供应商:协议类型、Base URL、API Key、自定义请求头
models 模型:别名、模型 ID、协议、上下文窗口、model_params / execution_params
prompt_templates 提示词模板
agents SubAgent:模型绑定、runtime_params、ext_config(工具/MCP/技能/人设)
mcp_servers MCP 服务:transport、url、headers
skills 技能包:文件数组(SKILL.md + 资源)
environments 环境:人格/画像/记忆、工具/MCP/技能开关、SubAgent 授权
sessions 会话:环境、提示词、供应商/模型与 model_snapshot(不依赖 Agent)
message_events 事件:user_message / model_reasoning / model_reply / model_retry / tool_call / tool_result / subagent / turn_notice / task_failed / model_reply_cancelled
config 全局设置(模型请求、工具与脚本、网络抓取、MCP 与权限开关)

界面布局

控制台采用「侧栏固定 + 内容区独立滚动」:.shell 占满视口并隐藏溢出,页面根容器 .sp-page 在内容区内滚动,滚动条只出现在内容区右侧、按需显示,不会再让整个页面出现滚动条。环境管理使用双栏固定高度布局(左右两栏各自滚动),对话页为三栏自适应。

对话交互(对齐 awake-claw)

  • 新建会话:控制台与工具栏弹窗都使用同一个创建对话框,必须选择环境、供应商、模型(提示词可选),标题可留空;创建时写入 model_snapshot,后续对话不再依赖 Agent。后端同样校验,缺少环境会返回 SESSION_ENVIRONMENT_REQUIRED。
  • 右侧模型参数面板:环境 / 供应商 / 模型 / 提示词 / API 协议(对话补全、响应接口、消息接口),以及上下文窗口、最大历史条数、历史 Token 比例、输入模态、模型参数与执行参数,改动 700ms 后自动保存。
  • 普通参数与高级参数:协议常用字段(温度、最大输出、推理强度、流式)与上下文窗口、历史条数、历史 Token 比例、模态直接平铺;top_p、惩罚项、结构化输出、工具行为、流式缓存等收进「高级参数」折叠,标题上实时显示「N 项已设置」,收起也能看出有没有配过。字段名与枚举值全部中文,悬浮提示里给出原始参数名。
  • 单一数据源:参数修改以整对象向上提交,切换会话或刷新后都能正确回显;会话切换前会先落库待保存的改动,避免写到别的会话。
  • 模型参数按协议动态生成:只展示当前协议合法的字段(例如 max_tokens 只出现在 Anthropic,reasoning_effort 只出现在 OpenAI chat),并按分组折叠,避免发出会被 400 的键。
  • 执行参数:max_tool_call_rounds(工具轮次上限)、max_retries(模型请求重试次数,默认 2,0 表示跟随设置页全局值)、tool_call_retention_rounds(历史中保留最近几批工具明细)。429 限流、5xx 与网络错误会按退避自动重试,重试过程写入 model_retry 轨道行,无需手动点按钮。重试计数按事件线累计(重试 ×1、重试 ×2…),与 awake 的 retry_count 语义一致,不再显示 1/2 这种每次请求都重置的分式。
  • 历史裁剪:history_token_ratio 按「字符数 × 比例」估算历史 Token(默认 0.35),预算 = 上下文窗口 − 输出预留 − 系统提示占用;超预算时从最早的消息开始丢弃,且不会以 tool 消息开头。优先级为会话 → 模型默认。
  • 事件线(直接移植 awake 的 ConversationTimeline):用户消息是右对齐的浅蓝气泡;助手侧是一条带竖线的事件轨道,思考、工具、回复、SubAgent、重试、失败全部是同级轨道行,图标同一列、正文统一缩进 22px。思考行默认收起,摘要取最近 160 字(与 awake 的 eventSummary 一致),展开才显示全文。工具行展开后是「参数 / 返回」两栏,失败行展开是完整错误并带「重试本轮」。
  • 两套外形,一套结构:控制台与工具栏弹窗共用同一套时间线 DOM 与样式(弹窗只是把字号、间距、图标尺寸压小),差异仅在容器宽度;两端共用 frontend/shared/timeline.js 的轮次解析,避免语义分叉。
  • 删除与清空:每条轮次底部有「删除本轮」;失败事件行内也可直接重试或删除。弹窗会话抽屉里可「清空会话」或删除整个会话,操作前均有二次确认。

SubAgent

Agent 不再参与普通会话,只作为 SubAgent 使用(参考 awake-claw 的 coding subagent):

  1. 在「SubAgent」页创建:绑定供应商/模型/提示词,勾选工具、技能、MCP,设置运行参数。
  2. 在「环境 → SubAgent」授权:选择访问模式(read_only 只能读取页面;workspace_write 可点击、输入、执行脚本),脚本执行需单独允许。
  3. 主 Agent 拿到 subagents_list / subagent_run 两个工具,派发时给出 agent_id、title、task、context。
  4. SubAgent 拥有独立系统提示与消息序列,不加载父会话历史,也不能再派发 SubAgent;执行过程以 subagent 事件嵌套展示。
  5. 未授权任何 SubAgent 时,这两个工具不会下发,避免模型反复试探。

能力开关语义(与 awake-claw 一致)

  • include_new = true:显式启用集合 ∪ 全部现存资源(等价于全量可用)
  • include_new = false:仅显式启用的资源
  • 会话使用的工具由 环境资源 决定;SubAgent 的工具由 SubAgent 勾选 ∩ 环境资源 决定,并按访问模式收窄
  • 环境开启「注入技能元数据」后,已启用技能的「名称 + 描述」写入 system prompt,模型再按需 skills_view 加载全文

设置

设置页按分组渲染(键名与后端 config_meta.js 一致,避免两边各写一份):

分组 内容
模型请求 请求超时、网络层重试、重试退避、默认工具轮次
工具与脚本 工具超时、脚本超时、交互后等待
网络抓取 web_fetch 开关、抓取超时、返回字符上限、域名白名单
MCP 连接超时、工具缓存
权限 调试通道权限状态(安装级)、allow_script 与 CDP 回退开关

设置页结构对齐 awake-claw:单面板内按分组堆叠,分组标题栏 + 两列行(说明 / 控件),右侧标注控件类型。

没有「新会话默认」这类配置:新建会话必须显式选择环境、供应商、模型(提示词可选),因此默认环境 / 默认提示词 / 默认模型 / 全局备注都不再存在,避免出现「看着配了、实际没生效」的隐式状态。

供应商配置

  • 协议:OpenAI 官方 / OpenAI 兼容端点 / Anthropic
  • 请求路径:下拉选择,由协议决定——OpenAI 提供「对话补全(/chat/completions)」与「响应接口(/responses)」,Anthropic 固定 Messages 接口、不显示该字段;旧数据中的自定义路径会作为额外选项保留
  • 自定义请求头:逐行表格编辑(名称 / 值 / 删除),支持批量导入——Key: Value、Key=Value、Key,Value 三种写法,也可直接粘贴 JSON;名称与值会自动去掉首尾空格与包裹引号,重复名称以最后一行为准

内置工具(74 个:61 个默认 + 13 个需显式启用,其中 40 个只读)

  • 标签页与导航(10):list_tabs、get_active_tab、open_tab、switch_tab、close_tab、go_back、go_forward、reload_tab、wait_for_navigation、list_frames
    • switch_tab / open_tab 会把目标标签页绑定为当前工作标签页,后续页面工具自动跟随
    • wait_for_navigation 以「URL 变化或匹配 + 加载完成」为条件,避免用固定 sleep 猜加载
  • 页面读取(13):get_page_snapshot、get_element_info、query_elements、query_by_text、extract_text/links/table/form/meta/jsonld、extract_buttons_info、extract_all_anchors、get_whole_html
    • 选择器支持 #host >>> .inner 语法穿透 shadow DOM;快照会返回元素是否在视口、是否被其他元素遮挡
  • 页面交互(9):click_element、hover_element、input_text、press_key、submit_form、set_checkbox、select_option、scroll_to、wait_for_element
    • 点击会依次派发 pointerover/mouseover/pointerdown/mousedown/pointerup/mouseup/click,兼容只监听 mousedown 的组件
    • 写入走原生 value setter + InputEvent,React / Vue 受控组件同样生效
  • 页面改写(7):set_text、set_html、set_attribute、remove_elements、replace_whole_html、execute_script、assert_page_state
  • 通用工具(14):http_request、web_fetch、set_storage/get_storage、encoding_convert、url_encode/decode、jwt_decode、jsonpath_query、regex_extract、random_*
    • web_fetch 抓取 http/https 网页并抽取正文,默认返回 Markdown(标题、列表、链接、代码块),支持纯文本 / 原始 HTML、字符上限、超时与域名白名单;无法访问浏览器内部页面与本地文件
  • 编排与 SubAgent(4):tool_list、batch_execute、subagents_list、subagent_run
  • 技能(3):skills_list、skills_view、skills_read_file
  • 需在环境资源里显式勾选才会下发(13):crypto_encrypt/decrypt、hash_digest、hmac_sign、rsa_*、mcp_service_*、mcp_tool_list、get_mcp_service

工具默认集只包含「操作浏览器」需要的能力;配置类与加解密类工具标记为 expose: admin,避免模型误用。每个工具标注了 readOnly,SubAgent 处于只读模式时只会拿到这 40 个只读工具。

环境管理

环境页沿用 awake-claw 的结构:左侧环境列表 + 右侧分页签编辑器,改动自动保存(文本 600ms 防抖,开关立即保存)。

  • 环境资源:MCP / 技能 / 工具三类,各自带「自动包含新增资源」开关。开启时默认全部可用(加解密与 MCP 配置类工具仍需显式勾选),关闭后按勾选精确控制;默认生效的条目会标「自动包含」,关闭开关时会把当前生效状态固化成显式勾选,不会突然清空。
  • 上下文四段:记忆、用户画像、人格、行为,各自可设字符上限,按「人格 → 画像 → 行为 → 记忆」顺序注入系统提示。
  • SubAgent:总开关控制是否派发;列表始终可勾选,授权某个 SubAgent 会自动打开总开关,另提供「全部授权 / 全部取消 / 刷新列表」,未创建时给出跳转入口
  • 预览:先保存当前配置,再按「系统环境 → 环境上下文 → 提示词 → 技能 → 工具规范 → 输出约束」生成完整提示

新建环境时可先填名称与四段上下文;重命名、删除都在编辑器右上角。

脚本执行与严格 CSP

execute_script 默认关闭,需在「设置 → 权限」显式开启。它先在页面主世界执行(能访问页面自己的 jQuery / React / Vue 实例):

  • 普通页面:直接执行,返回可序列化结果
  • 严格 CSP 页面(script-src 不含 unsafe-eval):new Function 会被拦截,此时自动回退到 CDP Runtime.evaluate,该通道不受页面 CSP 约束;可在设置中关闭「使用调试通道」,关闭后在严格 CSP 页面直接返回 SCRIPT_CSP_BLOCKED
  • debugger 是 Chrome 的安装级权限(Chrome 不允许把它声明为可选权限,运行时 permissions.request 会报 “Only permissions specified in the manifest may be requested”),因此随扩展安装声明;修改清单后需在扩展管理页重新加载一次
  • 调试期间浏览器会显示「正在调试此浏览器」,执行结束立即断开;DevTools 已打开该标签页时无法 attach,会明确报错

技能库

技能库按 awake-claw 的卡片式管理:卡片显示启用状态、是否可用(缺 SKILL.md 会标红)、文件数与描述;「查看」为只读,「编辑」打开左侧文件树 + 右侧全文编辑,可新建子目录文件、删除文件;导出为 JSON。

导入只有一个入口:点击「导入」直接唤起目录选择,不再有二次确认弹窗。每个包含 SKILL.md 的目录生成一个技能,其余文件按相对路径保留(如 references/api.md);没有 SKILL.md 的单个 Markdown 各自成为技能;选中后立即写入并提示导入数量与被跳过的项,同名技能会被覆盖。

MCP 支持范围

传输 支持 说明
streamable_http ✅ 推荐,POST JSON-RPC 到服务端点
http ✅ GET /tools + POST /call 网关模式
sse ✅ endpoint 事件 + 消息端点,按 JSON-RPC id 对齐
stdio ❌ 浏览器扩展无法启动本地进程,保存时即被拒绝

界面沿用 awake-claw 的交互:卡片显示启用与连接状态(未测试 / 已连接 / 失败),编辑弹窗支持请求头逐行编辑与批量粘贴、保存前「测试连接」;「查看」弹窗分「工具 / 资源 / 提示词」三段,工具可展开 input_schema,并支持「测试全部」。

开发与验证

npm run build:background   # 仅构建 service worker
npm run build:ui           # 仅构建界面
npm test                   # 离线冒烟测试(fake-indexeddb + 桩 fetch)
npm run test:e2e           # 真实 Chrome 端到端(需先 npm run build)
npm run test:ui            # 真实 Chrome 逐页渲染与交互(需先 npm run build)

npm test 覆盖三段链路:

  1. scripts/smoke.mjs —— 模块 CRUD、脱敏、唯一性校验、级联解绑、会话快照(含历史 Token 比例)、路由错误码(47 项断言)
  2. scripts/smoke_chat.mjs —— 流式输出、工具循环、事件落库、HTTP 错误处理(19 项断言)
  3. scripts/smoke_tools.mjs —— function calling 专项:工具不变量、环境工具开关、多轮 tool_calls ↔ tool 结果 配对、参数自我纠正、重复失败拦截、轮次上限收尾、模型重试、工具结果保留轮数、SubAgent 派发与只读约束、历史 Token 预算、web_fetch 正文抽取与域名白名单、新增设置项、请求头批量解析、MCP 传输与调试通道配置、默认自动重试与累计计数(80 项断言)

npm run test:e2e 会安装未打包扩展、起一个桩模型服务,让模型按脚本下发 15 次工具调用,真实执行「读取标签页 → 快照 → 输入 → 按键 → 点击 → 脚本执行(含 CSP 回退)→ 新标签页 → 切换 → 关闭」,并对页面 DOM 做最终断言(32 项)。

npm run test:ui 在真实浏览器中逐页打开控制台,检查渲染与运行时错误,验证「新建会话」对话框、模型参数回显、设置保存、内容区独立滚动(页头固定)、供应商请求路径与请求头批量导入、环境 SubAgent 授权、技能目录导入、弹窗尺寸,以及桌面与 H5 两套事件线的结构与样式、H5 删除与清空(74 项)。

已知限制

  • 界面产物未做 minify:当前沙箱环境 esbuild 压缩大 chunk 会异常退出;功能不受影响,可用 build.minify 在正常环境开启
  • 浏览器内部页面(chrome://、edge://)无法注入脚本,工具会返回明确错误,并提示用 open_tab 打开普通网页
  • debugger 为安装级权限,安装/更新扩展时 Chrome 会额外提示「调试此浏览器」;修改清单后需在扩展管理页重新加载才能生效
  • MCP 的 stdio 与本地文件系统能力受浏览器安全模型限制,不可用(界面与接口均不提供该选项)
  • web_fetch 受同源策略与站点反爬限制:需要登录、Cloudflare 挑战或 robots.txt 禁止的页面可能抓不到;跨域请求依赖扩展的 <all_urls> 主机权限
  • 关闭弹窗会结束正在进行的一轮对话(长连接断开即取消),长任务请在控制台执行
  • API Key 与 MCP 请求头以明文存放于扩展私有 IndexedDB(与 awake-claw 的 SQLite 存放方式一致),请勿在共享设备上使用生产密钥
  • execute_script 的 CDP 回退通道按标签页整体求值,暂不支持指定 frameId(用主世界通道时可传 frameId)
  • 文件上传(<input type="file">)无法通过 DOM 赋值伪造,需要 CDP DOM.setFileInputFiles,当前未提供对应工具

参考图