浏览器工具栏
只放与当前网页直接相关且频繁使用的动作:导航、地址、保存当前页、打开书签、外部打开和 Browser ⋯。
点击、滚动、键盘输入、导航和关闭页面都不会暂停 Agent。用户输入和自动化同样适用,包括对 OpenProgram 本身的自动化。只有会话执行控件能暂停或取消任务。浏览器资源不维护独立的写入禁令。
现有页面输入通知路径错误地请求暂停执行,残留页面禁令可能在创建它的执行结束后继续存在。移除该路径及独立禁令检查,同时保留执行派发守卫、归属检查和当前 frame 验证。
目标消失时丢弃其 session,返回包含最后 URL 的可操作恢复信息。通过观察新打开的精确 URL 恢复,绝不重放修改操作或选择无关标签。Agent 用新观察继续任务;缺少认证或未保存状态时如实报告,不虚构恢复。
浏览器截图保留 ToolReturn 图像与结构化错误。执行器关闭后,存活服务器不得继续向已关闭默认执行器提交工作。恢复必须遵守任务取消与未决外部效果限制。
已实现并通过独立审查:页面事件保持执行运行;显式会话暂停仍阻止派发;旧页面禁令不能阻止新执行;关闭的目标提供可用恢复信息;截图保留图像;关闭错误由所属生命周期处理。验证受影响的 Desktop/Python 组件、合同、文档链接及安装版 App。完成前必须通过独立规格与质量审查。
新建 Pane 只负责选择内容类型;进入 Browser 后才显示网页导航、书签、History 和资料导入。浏览器工具栏只处理当前网页和浏览资料,整个窗口的菜单只处理 OpenProgram 与 Pane。两类设置共用同一 Settings 页面,但使用不同入口。
当前问题来自内容入口、浏览器主页和资料管理共用一个页面。设计先分离职责,再定义每个页面出现的控件。
网站书签复用标签页 favicon 渲染:已保存图片、网站自身 /favicon.ico、Lucide 浏览器默认图标,依次回退。仅接受 HTTP(S) 和图片数据,不发送 referrer,不使用第三方 favicon 服务。新书签保存当前网页图标,再次查看相同 URL 时更新已保存图标,加载时空图标不清除原值。书签栏保持原高度,依次显示书签栏内容、双箭头溢出入口、分隔线和最右侧“所有书签”。所有书签打开现有管理页,其他书签和移动端书签保持原层级。文件夹继续显示文件夹图标。验收覆盖导入书签、图标失败和更新、溢出导航以及管理入口。参考 Chrome 官方书签帮助和用户提供的截图。
原生网页加载时,刷新按钮切换为强调色的 Lucide X,标注“停止加载”;工具栏下方显示细条形的不定进度指示,不改变工具栏高度。停止按钮取消加载;完成、失败或取消后隐藏指示并恢复刷新。指示使用原生加载事件,不显示虚构百分比;减少动态效果模式下保持静态。
网页使用 beforeunload 阻止刷新或导航时,在其当前所属窗口显示原生确认框。默认按钮和取消操作都是留在页面;选择离开页面后,仅允许当前被阻止的操作继续。页面失去所属窗口、已经销毁或对话框失败时保持页面。普通刷新不额外确认。使用 Electron 的 will-prevent-unload 事件;本次不修改标签关闭和 App 退出策略。
普通标签和分栏成员优先显示网站 favicon;加载中、加载失败或解码后完全透明时,显示已有的动态 Lucide 浏览器图标。桌面主进程使用页面所属 session 读取图标,只允许 HTTP(S) 和图片 data URL,限制为 256 KiB 和五秒;以图片 data URL 传给渲染端,支持检测透明像素。导航和销毁取消读取,过期结果不能覆盖当前页面。重新打开保留的页面时,状态快照带上当前 favicon。历史记录保存网站原始图标 URL。
空白 Pane 只显示 Files、New chat、Browser、Terminal。地址栏、快捷网站、Bookmarks 和 History 不出现在这里。
Files、New chat、Browser、Terminal 都使用相同尺寸的圆角图标容器和 Lucide 线性图标;Files 使用蓝色、New chat 使用绿色、Browser 保留橙紫色、Terminal 使用紫色。颜色只帮助识别内容类型,不改变卡片层级、交互状态或可访问名称,也不引入品牌 Logo、外部素材和额外动画。
选择 Browser 后原位进入浏览器主页;主页与实际网页使用同一套地址栏和书签栏结构。主页中无当前网页语义的 Back、Forward、Reload、Home、Bookmark 和外部打开保持可见但禁用,地址输入、Bookmarks、Import 和 Browser ⋯ 可用。
普通链接、表单提交、脚本赋值和同文档导航继续由当前 WebContentsView 提交,并只更新当前 WebTab 的 URL、标题和 History;不得新建标签。只有页面明确请求新浏览上下文(target="_blank" 或 window.open)时,main 进程才把经过校验的 HTTP(S) URL 转换为一个具有独立 id 的 WebTab。新 WebTab 立即成为活动标签;当前已经位于 /chat 或 /s/<id> 时不得再推送 /chat,避免会话路由同步覆盖 popup 的活动状态。
原生网页区域直接使用 Electron context-menu 命中参数。HTTP(S) 链接显示 Open Link in New Tab 和 Copy Link Address;可编辑内容显示 Undo、Redo、Cut、Copy、Paste 和 Select All;普通页面显示 Back、Forward 和 Reload。Open Link in New Tab 复用同一 popup 入口,因此与页面自己的 window.open 具有相同的 URL 校验、唯一标签和立即激活语义。菜单动作只作用于产生该菜单且仍由同一窗口拥有的 WebTab。
Agent 在聊天中打开的悬浮网页预览记录创建时的 session tab。它只在该会话作为当前中心内容时显示;切换到其他聊天、普通 Browser tab 或非聊天页面时,renderer 必须从原生可见集合移除该 WebTab 并恢复用户网页缩放。返回原会话时复用同一 WebTab、URL、滚动和表单状态,不重新加载。用户关闭预览后,恢复入口也只出现在所属会话。
地址栏右侧的星标只保存或移除当前页;相邻的 Bookmarks 按钮打开完整书签页。Browser home 只显示用户维护的快捷网站,不展开全部书签。
完整书签页顶部固定页面标题、搜索框和页级菜单;左栏只显示可折叠的文件夹树并高亮当前目录,右栏只显示当前目录的直接子项。书签行使用 favicon、标题和单一 ⋮ 菜单,文件夹行进入对应目录;不再把整棵树、URL 和编辑/删除按钮同时铺在一个列表里。左右列表行统一为 36px,搜索框沿用全局 30px 控件高度,行内图标按钮为 28px,页头为 52px;右侧列表的首屏内边距为 16px。Pane 变窄时目录树移到内容列表上方,不能直接消失。
Browser home 和实际网页默认在地址栏下方显示同一行书签。用户可以从 Browser ⋯ 或 Settings 关闭;窄分屏临时隐藏该行,仍可通过 Browser ⋯ 中的 Bookmarks 访问全部内容。
Chromium 的 Bookmarks bar 是书签栏容器,不作为普通文件夹按钮显示。该容器的直接子项按原顺序进入栏内;Other bookmarks 和 Mobile bookmarks 保留在“所有书签”管理页中;栏位右侧依次是溢出入口、分隔线和“所有书签”。普通根级书签继续作为栏内项目。进入溢出菜单的项目不能在可见栏内保留被裁切的半个按钮;最后一个可见按钮必须完整显示背景和两侧圆角。
单行书签栏不出现水平滚动条;被宽度截断的项目由右侧溢出入口列出。菜单固定为 280px 宽,过长标题使用省略号;文件夹行在既有 14px 图标位显示 Folder 图标,并以右箭头进入下一级菜单,不把完整路径拼进一行。网站行显示书签 favicon;导入数据未包含 favicon 时按 URL 获取,加载失败时显示共用的浏览器默认图标,不能留下无内容的空白位。桌面 App 中鼠标悬停书签栏文件夹立即打开该文件夹,横向移到相邻文件夹时菜单随目标切换,不设置额外等待时间。连续切换文件夹时复用同一个菜单视图,只替换菜单数据,不能反复重建视图并重新解码已经显示过的 favicon。菜单的原生覆盖层从书签栏下缘开始,不能遮挡书签栏按钮的鼠标命中区域。每一级菜单高度受当前窗口约束,并支持鼠标、触控板与键盘操作。
窗口菜单的 Settings 打开 OpenProgram 设置;Browser 的 ⋯ 直接打开其中的 Browser 分区。工具栏不增加常驻齿轮,也不实现第二套浏览器设置存储。
分屏、退出分屏和 Pane 排列适用于 Files、Chat、Browser、Terminal,不属于当前网页动作。它们放在 Tab/Pane 控件或 Tab 上下文菜单,不出现在浏览器工具栏。
Chromium 的 bookmark bar、other bookmarks 以及嵌套文件夹按原有层级和顺序进入 OpenProgram bookmark tree;导入不得把书签压平成主页下方的独立条目。
浏览器 ⋯ 和窗口 ⋯ 都使用各自触发按钮的实际屏幕矩形定位,菜单右边缘与按钮右边缘对齐,垂直间距为 4px;二者不能共用位置或内容。
记录按本地日期分组,每行只显示时间、favicon、标题、域名和操作;完整 URL 不再单独占用第二行。
来源浏览器、profile 和数据类型分别确认。OpenProgram 不读取或修改用户正在使用的源 profile。
浏览器区域分为当前网页、浏览器资料和整个窗口三层。按钮是否常驻由操作频率、当前页面相关性和窄分屏占用共同决定。
| 位置 | 常驻动作 | 窄分屏规则 |
|---|---|---|
| 地址栏左侧 | 后退 · 前进 · 刷新/停止 · 主页 | 520–719px 将 Home 移入 ⋯;低于 520px 再将 Forward 移入 ⋯。Back 与 Reload/Stop 始终保留。 |
| 地址栏 | URL、搜索输入与安全状态;加载期间 Reload 原位变为 Stop。 | 始终占据剩余宽度,最低可用宽度 160px;不换行。 |
| 地址栏右侧 | 收藏当前页 · 书签 · 外部打开 · 浏览器菜单 | 520–719px 将 Bookmarks 与 Open externally 移入 ⋯;星标和 ⋯ 始终保留。 |
| 地址栏下方 | 用户可选的单行 bookmarks bar,直接显示 Bookmarks bar 的子项;放不下的条目进入双箭头溢出入口,随后是分隔线与“所有书签”管理入口;其他根目录在管理页中保留。 | 低于 560px 不渲染该行,从 Browser ⋯ 中打开 Bookmarks;禁止水平滚动条。文件夹与溢出菜单的最大高度不得超过当前窗口可用高度,并允许纵向滚动。 |
只放与当前网页直接相关且频繁使用的动作:导航、地址、保存当前页、打开书签、外部打开和 Browser ⋯。
⋯新浏览器标签、页内查找、缩放、打印、书签、历史、下载、显示书签栏、导入浏览器资料、清除浏览数据、浏览器设置。
New pane/window、Pane 布局、OpenProgram Settings、Help 与 About。它不再直接放 Bookmarks、History 或网页级设置。
| 活动内容 | 悬浮预览 | 原生 WebTab 约束 |
|---|---|---|
| 创建预览的聊天 | 显示;返回该聊天时恢复原位置和尺寸。 | 使用 PiP bounds 和布局缩放;保持同一 WebContentsView。 |
| 其他聊天 | 隐藏;不显示恢复入口。 | 从 syncVisible 集合移除并恢复用户 zoom factor。 |
| 普通 Browser tab、分屏中的同一网页 | 隐藏。 | 普通 pane 独占该 WebTab 的可见 bounds,不保留 PiP 布局缩放。 |
| 用户在所属聊天关闭预览 | 隐藏;所属聊天显示恢复入口。 | 保留后台 WebTab,不暴露为其他会话的 turn surface。 |
下面是信息结构验收图。切换状态即可检查控件是否出现在正确层级。
参考产品用于确认可见行为,平台文档用于确认可实现边界。OpenProgram 不复制完整 Chromium importer。
Files、New chat、Browser、Terminal 作为一级内容类型;浏览器控件只在 Browser 内显示。
采用内置浏览器保持自己的 profile。需要既有资料时,由用户明确发起导入。
修改后采用星标保存当前页;书签栏可开关;完整管理器独立存在。OpenProgram 保留三层,但针对分屏定义更严格的收缩规则。
修改后采用内置浏览器保持独立状态,Cookies 与历史清理归桌面 App Settings。OpenProgram 增加 Browser ⋯ 深链,但不复制设置存储。
当前浏览上下文中的导航原位提交;页面明确请求新浏览上下文时创建并激活新标签。OpenProgram 保留这一区分,但把 native popup 转换为受中心标签状态管理的 WebTab。
修改后采用webContents 提供链接、选择区、编辑状态和 frame 命中参数;Menu.popup 提供当前 OS 的原生菜单。OpenProgram 采用有限动作集,不暴露 DevTools 或任意协议打开。
组件不作为 Electron JavaScript API 暴露,且不提供通用 Cookies import 实现。
不复制setWindowOpenHandler 接收已解析 popup URL,context-menu 提供链接、选择区和编辑命中参数。Menu.buildFromTemplate 和绑定所属 BaseWindow 的 menu.popup 是 main 进程的原生上下文菜单入口。renderer 只传递 main 进程签发的 opaque source/profile id。文件路径、源浏览器可执行路径和 Cookie 值都不能通过 renderer 自由指定。
| 页面意图 | main 进程 | renderer 状态 |
|---|---|---|
| 当前上下文导航 | did-navigate / did-navigate-in-page 回报同一 record 的状态;不发送 popup 事件。 | updateWebTab 原位更新 URL、标题和 favicon,id 与活动标签不变。 |
target="_blank" / window.open | setWindowOpenHandler 拒绝 native 子窗口;仅将有效 HTTP(S) URL 和 opener id 发给拥有该 View 的窗口。 | openPopupWebTab 创建唯一 id 并立即设为 active;已在聊天 surface 时保持当前 route。 |
| 网页右键链接 → Open Link in New Tab | context-menu 校验 exact owner 和 URL 后复用上述 popup 事件;Copy/Edit/Navigation 动作直接绑定产生菜单的 webContents。 | 新标签与页面 popup 相同;菜单关闭或 stale owner 时不执行跨标签动作。 |
网页内容、renderer 与 main 进程之间只传递完成动作所需的有界状态;资料导入不是 profile 迁移,只复制用户明确选择的数据。
| 边界 | 约束 | 失败结果 |
|---|---|---|
| renderer → main | source/profile 使用 main 返回的 opaque id;数据类型使用 allowlist;renderer 不能传文件路径或可执行路径。 | 拒绝请求 |
| 网页内容 → main | popup 和右键链接只接受解析后的 HTTP(S) URL;动作绑定产生事件的 exact WebTab owner。file:、javascript:、已转移/关闭的 record 和伪造 opener 均不得创建标签或导航其他 View。 | deny / no-op |
| 源 profile | 只读发现;真实路径必须位于已发现 browser root 内;拒绝符号链接逃逸。 | source_invalid |
| 临时数据 | 目录 0700、文件 0600;成功、失败或超时后都删除;日志只记录来源标签、类型、计数和错误码。 | 清理 + 稳定错误 |
| 目标 profile | History 和 Bookmarks 合并;Cookies 通过 Electron API 写入,不替换目标数据库。 | 保留导入前数据 |
| 并发与取消 | 全 App 同时只允许一个导入任务。发起 renderer 生成有界 request id;只有同一 renderer 可以取消。取消在解析阶段边界、临时浏览器启动/CDP 等待以及每条 Cookie 写入前后检查。 | import_busy / import_cancelled |
| 取消后的目标状态 | 接受取消后不合并 History 或 Bookmarks,临时浏览器终止且临时目录删除。Electron Cookie API 没有事务;取消前已经完成的 Cookie 写入保留,取消后不得继续写入。 | cooperative stop |
网页按会话归类,默认收进右侧可折叠的会话资源面板。入口与资源类型的完整设计见 会话资源。网页记录继续保留真实会话归属与固定状态,手动网页及显式分屏保留顶部位置。
每项验收都对应一个外部可观察结果。设计状态和实现证据分列,不以文档存在本身证明功能完成。
| 可观察结果 | 当前状态 | 实现证据 |
|---|---|---|
普通页面导航保持当前 WebTab id 与活动状态;target="_blank" / window.open 创建唯一 WebTab,并在创建后持续保持活动,不被原聊天 route 覆盖。网页链接右键显示 Open Link in New Tab 与 Copy Link Address;普通/编辑上下文显示对应 Navigation 或 Edit 动作,所有动作只作用于 exact owner。 | 已实现并通过默认 App 验收 | desktop-bridge.ts popup 路由合同;apps/desktop/main.js WebContentsView 上下文菜单;check-web-split.mjs;check-webtab-navigation.js。独立 specification 与 quality review 均通过;安装版中 popup 在创建后连续观察 2 秒保持 active 且 /s/<id> 不变,普通导航保持 tab 数量与 id,HTTP(S) 链接原生右键菜单显示 Open/Copy 与页面导航动作。 |
| 新建 Pane 只显示 Files、New chat、Browser、Terminal;四个入口使用同尺寸、不同语义色的圆角图标容器,DOM 中不存在浏览器专属控件。 | 已实现并通过默认 App 深浅主题验收 | new-tab-page.tsx;check-built-in-browser.mjs 的有效级联与语义色 mutation 检查 |
| 选择 Browser 后原位显示与网页页签相同的地址栏和书签栏结构、导入入口和快捷网站;无当前网页语义的动作保持可见但禁用。 | 已实现并通过默认 App 验收 | browser-home-page.tsx;check-built-in-browser.mjs;实际 App 中 toolbar / bookmarks bar 为 40px / 30px |
标准宽度的 Browser toolbar 按顺序显示 Back、Forward、Reload/Stop、Home、地址栏、当前页星标、Bookmarks、外部打开和 Browser ⋯;不显示分屏与 Settings 齿轮。 | 已实现 | web-tab-pane.tsx;check-built-in-browser.mjs;check-web-split.mjs |
浏览器 ⋯ 提供 Bookmarks、History、Downloads、书签栏开关、Import、Clear browsing data 和 Browser settings;窗口主菜单只保留 App、窗口与 Pane 操作。桌面弹层按菜单的 scrollWidth/scrollHeight 回报固有尺寸,不能按当前裁剪高度递归缩小。 | 已实现 | browser-controls.tsx;menu-overlay/context-menu/page.tsx;check-built-in-browser.mjs |
书签栏默认显示;用户关闭后保持关闭;直接显示 Bookmarks bar 的子项,双箭头溢出入口可访问放不下的项目,随后是分隔线和“所有书签”管理入口。进入溢出菜单的项目不再残留被裁切的按钮,最后一个可见按钮必须完整显示背景和两侧圆角。桌面文件夹悬停打开并可横向切换;鼠标从文件夹按钮跨入弹层或子菜单时保持打开,鼠标同时离开按钮及全部菜单面板后在 120ms 内关闭,不要求额外点击。文件夹菜单固定为 280px 宽,标题省略,嵌套文件夹逐级展开;文件夹行显示 Folder 图标,网站行显示 favicon,加载失败时显示共用的浏览器默认图标,不保留空白图标位;Pane 低于 560px 时隐藏书签栏,但 Bookmarks 页面仍可到达。 | 验收条件 | test_tab_favicons.py、bookmark-favicons.test.mjs、check-built-in-browser.mjs;默认 App 检查图标、溢出菜单和管理入口。 |
Bookmarks manager 使用顶部搜索、左侧文件夹树和右侧当前目录列表;普通行只保留 favicon/文件夹图标、标题和 ⋮。左右列表行均为 36px,页头为 52px,窄 Pane 改为上下布局。 | 已实现并通过默认 App 密度验收 | builtin-tab-pane.tsx;center-tabs.module.css;check-bookmarks.mjs;默认 App 实测页头、文件夹行、内容行、搜索框、图标按钮分别为 52 / 36 / 36 / 30 / 28px |
Browser settings 与窗口 Settings 使用同一路由和同一配置源;Browser ⋯ 直接打开 Browser 分区,toolbar 不显示常驻齿轮。 | 已实现 | /settings/browser;browser-settings.tsx;browser-prefs.ts |
| 导入对话框列出来源浏览器、profile 和支持的数据类型;开始前关闭不产生目标变更。执行期间原 Import 按钮原位变为 Cancel,关闭按钮禁用;接受取消后显示稳定的取消结果并释放全局导入占用,下一次导入可以开始。 | 已实现并通过默认 App 验收 | browser-import:run/cancel IPC;browser-profile-import.js 取消自检;check-webtab-navigation.js 的 sender ownership、lease release 与 window cleanup 检查;check-built-in-browser.mjs。安装版实际识别 Chrome 的 3 个 profile;运行时显示 Cancel 且禁用关闭按钮,取消返回 import_cancelled,随后新请求不再返回 import_busy。 |
| History 按日期分组,至少 1000 条时保持 36–40px 行高,搜索和滚动可用。 | 已实现并通过默认 App 规模验收 | web-history.css 为 38px;History 分页上限 5000,搜索在 main 进程完成;存储 self-check 覆盖 5000 条上限。在安装版 App 的现有 5000 条记录上逐批显示到 1000 行,三次增量渲染为 241.6 / 235.1 / 256.2ms,行高全部为 38px,滚动到底部后末行可见;google 搜索在 299.4ms 内得到 250 条匹配结果。 |
| 内置网页下载进入系统 Downloads 目录;Downloads 页面显示实时进度和最终状态,并支持打开文件、在 Finder 中显示、取消进行中任务和清除记录。 | 已实现,安装版通过 | apps/desktop/main.js 的 will-download 与 downloads:* IPC;builtin-tab-pane.tsx;check-webtab-navigation.js。安装版 App 实际完成 42 B 附件下载,并取消一个 32 MB 进行中任务;页面分别显示 Completed、Cancelled,取消后 active=false,测试记录可清除。另一次安装版下载验证中,Open 使用系统关联应用打开 58 B 文本文件,Show in Finder 定位并选中同一文件;随后已清除测试记录并将文件移到废纸篓。 |
当前网页支持 Find in page、Zoom in/out/reset 和 Print;命令只作用于请求窗口拥有的精确 WebTab。Print 首先调用系统打印;系统打印失败或没有可用 destination 时,由同一动作打开所属窗口的原生 Save PDF 对话框。用户取消系统打印或保存均返回未完成,不写入文件;系统打印成功时不得额外生成 PDF。PDF 先写入目标目录中的唯一临时文件,完成后再替换用户选择的路径,失败时保留既有目标。Find 提供上一处、下一处、匹配数与关闭,关闭时清除页面选择;⌘/Ctrl+F、⌘/Ctrl++/-/0、⌘/Ctrl+P 与菜单动作一致。Web 前端与桌面壳版本暂时不一致时,前端按 preload 实际暴露的能力启用动作;缺少新 IPC 的旧壳必须禁用对应动作且不能导致页面异常。 | 已实现,安装版通过 | apps/desktop/main.js 的 webtab:find/zoom/print IPC;web-tab-pane.tsx;check-webtab-navigation.js;check-built-in-browser.mjs。安装版在本地文档页找到 35 处匹配并可前进到第 2 处;Zoom 返回 100 → 110 → 100 → 100。验收机没有打印 destination,系统 Print 失败后实际出现所属窗口的原生 Save PDF 对话框,并从当前文档 WebTab 生成 1 页、8455 B 的 PDF,IPC 返回 true;测试文件已移到废纸篓。自动检查覆盖系统打印取消、保存取消、写入失败保留既有文件,以及 PDF 渲染期间失去 exact ownership 时不写文件。常驻 toolbar 与 tab 栏样式未改变。 |
| Bookmarks 保留来源根目录、最多 64 层文件夹和同级顺序;无效 URL 被过滤,重复导入不产生重复 URL 或空文件夹。 | 已实现 | apps/web/lib/tabs/bookmarks.ts;check-bookmarks.mjs |
窗口主菜单在桌面 App 和 Web 中都与触发按钮右对齐,按钮底部到菜单顶部的间距为 4px。桌面主菜单、Browser 菜单、书签菜单和 tab 右键菜单从 renderer 传入的 CSS 像素坐标必须按发送页面的 zoom factor 转换为 Electron DIP;在 80%、100%、125% 缩放下都保持贴近原触发按钮。由 renderer 动态提供的 Browser、书签和 tab 右键菜单只在该行实际有勾选、文件夹或 favicon 时渲染左侧图标槽;无图标项不保留空槽,文字从菜单行默认的 10px 内边距开始。 | 已实现 | main-menu.tsx;menu-overlay/context-menu/page.tsx;check-built-in-browser.mjs;check-center-tabs.mjs;check-webtab-zoom-bounds.js |
| 聊天输入框、模型、上下文等弹层未覆盖内置网页区域时,不得隐藏或重置原生 Web Page;只有可见弹层的矩形实际与网页矩形相交时,才暂停显示对应 WebContentsView。 | 已实现 | web-tab-bounds.ts 的矩形相交判断;web-tab-pane.tsx;check-web-split.mjs |
| 聊天内创建的悬浮网页预览只在所属会话显示;切到其他聊天、普通 Browser tab 或非聊天页面时必须隐藏并恢复用户网页缩放。返回所属会话时复用原 WebTab 状态;关闭后的恢复入口也只属于该会话。 | 已实现,自动检查与运行时复核通过 | web-tab-pip-store.ts;web-tab-pip.tsx;web-tab-pane.tsx;desktop-bridge.ts;apps/desktop/main.js;check-web-split.mjs 覆盖 owner chat、inventory 和无 pointer-up 切换;check-webtab-navigation.js 覆盖首次导航提交与 transfer commit 后的 zoom restore。安装版 production build 与默认 worker 健康检查通过。 |
Cookies 只进入 persist:webtabs;IPC、日志、History 和 renderer 不出现 Cookie 值。 | 已实现 | browser-profile-import.js self-check;apps/desktop/main.js |
| 来源损坏、浏览器缺失、临时进程超时和 Cookie 部分失败返回稳定错误码并保留原数据。 | 已实现 | browser-profile-import.js 与 browsing-history-store.js self-check |
| 依赖 PTY 的全屏终端程序。 | 当前限制 | 产品边界,不作为当前验收缺口。 |
| Passwords、自动填充、支付/地址数据和源浏览器接管。 | 明确排除 | browser-profile-import.js 的导入类型 allowlist。 |
| Chrome Web Store 与 Edge Add-ons 只作为普通网页打开;产品不提供商店安装、本地目录加载、CRX 下载、扩展运行时或管理页。 | 明确排除,代码已移除 | browser-extensions.html;check-no-browser-extensions.js;扩展不属于 profile data import。 |
可见验收只使用安装的 /Applications/OpenProgram.app、默认 18100 worker 和 ~/.openprogram。文档更新不改变 Agent 的网页控制协议。
本页是当前设计的规范性说明。实现发生变化时直接更新本页;历史修订由 Git 保存。
每个桌面窗口保留一个已分离的书签级联菜单视图。再次打开时重新挂载并更新菜单数据,不加载新文档。普通菜单保持原来的关闭行为。窗口清理销毁可见与缓存视图;已分离视图不能发送菜单操作。
渲染进程共用图标缓存,同一来源的并发请求合并,成功解码的32像素绘制结果保留30分钟,失败结果保留5分钟,最多256项。组件直接绘制缓存结果,不重新请求图片;来源变化使用新的缓存项。加载超时为5秒,不发送Referer,不使用第三方图标服务。跨域图片只绘制,不读取像素;可以读取且完全透明的图片仍使用回退图标。App重启后可以通过浏览器缓存重新加载,不新增持久化图标数据库。
bookmark-bar.tsx负责书签布局与菜单,browser-controls.tsx负责浏览器操作,favicon-cache.ts负责加载和有界缓存,tab-favicon.tsx负责显示。原生网页重复报告当前已加载的图标来源时,不清空或重新请求;页面导航仍清除原页面所有权。
验收:真实书签文件夹关闭后重开,即使服务端返回Cache-Control:no-store也不产生第二次图标请求。并发实例共用请求,失败和透明图片正确回退,来源变化后恢复,溢出图标保持隐藏,缓存过期和淘汰后允许重试。桌面测试覆盖视图复用、隐藏视图拒绝操作、位置更新和最终销毁。
参考:Canvas drawImage;Electron WebContentsView。实现证据:图标缓存与菜单复用已通过独立的功能和质量审查。favicon-cache.test.mjs覆盖并发合并、过期、超时和淘汰;check-bookmark-menu-cache.cjs覆盖文档复用、隐藏视图拒绝操作和销毁;test_tab_favicons.py覆盖真实React显示、重新挂载与文件夹重开。任务验证记录单独记录完整测试和已安装App验收。
浏览器工作流负责外层观察、动作和验证循环。每次规划请求启用stop_after_tool_round:共用Agent循环按原有参数校验、权限检查执行工具轮次,保留结果,然后返回工作流,不再请求下一条模型回复。它与安全上限max_iterations分开。默认Agent仍持续执行到最终输出。安全上限耗尽不可作为传输错误重试,避免重复已执行动作。要求最终结构化输出时不能同时启用此提前返回。
BrowserPageController向Playwright所属线程提交的每个操作均传递当前ContextVars,包括清理和最终验证。每次提交独立复制上下文,不把某次权限永久保存在控制器中;其他会话不能继承权限。页面隔离、绑定校验、权限审批和操作租约保持有效。
旧浏览器任务在存在明确绑定的当前Page时复用它,任务同时携带URL提示不会触发重载。明确绑定失效时返回失败,不另开替代页面。没有明确Page时保留原有URL打开行为。
验收通过公开浏览器任务、模拟模型和真实Runtime/Agent循环验证:一个动作仅执行一次,下一次请求验证,无迭代错误和重放,控制器关闭时保持同一会话身份。默认安全上限仍失败且不重放,明确当前Page复用且不打开或导航。实现证据:独立功能审查和质量审查通过。真实Runtime浏览器回归覆盖单次动作后验证、显式禁止规则、清理身份保留和失效绑定拒绝。Agent循环回归覆盖同步与异步选项传递、最终输出约束冲突,以及安全上限耗尽不可重试且工具只执行一次。任务验证记录单独记录完整测试和已安装App验收。
规划器通过明确的upload动作、已批准的本地路径和最新文件输入框ref选择文件。动作仍受沙箱读取规则、权限审批、页面所有权、取消和步数上限约束。文件输入框只暴露类型和所选文件名,不暴露内容或本地路径。选中文件与服务器接受分别验证;file_selected检查当前指定输入框,最终证据再次核验。MCP规划器在原有页面控制器中执行文件选择,不切换后端所有权。
验证内容填写value,text用于输入文字。无效参数返回明确原因;同一页面连续三次失败后停止,保留具体错误。规划器可以用stop报告阻碍,但不能因此成功。纠正参数后成功的调用正常继续。实际操作步数仍统计页面修改,不统计模型请求。
验收使用真实Runtime规划调用和测试专属无界面Chromium文件输入框,覆盖错误纠正、重复无效验证、停止、文件选择和读取、显式禁止、过期ref、沙箱读取、取消及独立服务器反馈验证。不上传用户私有文件,不操作实际注册。实现证据:独立规格与质量审查通过。回归覆盖两条 Runtime 规划路径、真实 Chromium 文件选择、服务器确认,以及读取后取消且不发送文件。完整发布验证与安装版验收另在任务记录中维护。