Skip to content

Releases: ricardochen1996/dsh-browser-use

v0.8.2

Choose a tag to compare

@github-actions github-actions released this 26 Oct 07:03

Fixed

  • The plugin page no longer calls itself up to date over a release the Market is holding back. The Market's desktop host withholds a release younger than a day (24 hours by default) and answers with updateAvailable: false while still naming the newer latestVersion; the page treated that as current and its check tooltip claimed there was no update — which is what a person saw after 0.8.1 was published. It now offers the newer version anyway, so the attempt either installs it or comes back as RELEASE_TOO_FRESH with the actionable explanation and a Force update retry, the bypass the Market documents in UPDATE-API-V1. lib/client.js; 2 new offline checks in test/inspector.mjs, taking the file to 65.

中文

修复

  • 市场按住一个版本时,插件页不再自称「已是最新」。市场的桌面宿主对发布未满一天(默认 24 小时)的版本会按发布年龄暂缓,回答里 updateAvailable: false,但 latestVersion 仍然指向那个更新的版本;页面把它当成已是最新,检查更新的提示也就说没有更新——0.8.1 发布后看到的就是这个。现在页面照常给出这个更新的版本:点击后要么直接装好,要么以 RELEASE_TOO_FRESH 明确告知发布年龄限制,并给出强制更新重试——正是 UPDATE-API-V1 文档里给客户端的绕过方式。lib/client.js;test/inspector.mjs 新增 2 项离线检查,检查数变为 65。

v0.8.1

Choose a tag to compare

@github-actions github-actions released this 26 Oct 05:55

Added

  • The bundle page detects its own updates. A Check for updates control now sits in the page's actions row beside Uninstall: it asks the Market's public update API (dshmarket's UPDATE-API-V1) for the newest published release, turns into Update to vX.Y.Z when one exists, follows the accepted install's progress, and reports the outcome — a UI refresh (refreshRequired), a DSH restart, a refusal code such as AGENTS_RUNNING, or the release-age hold that offers a Force update retry. Endpoints, envelope and restart ownership are discovered from the capabilities answer, so a Host that does not mount the Market simply shows no control (lib/client.js; 13 new offline checks in test/inspector.mjs, taking the file to 63).

Fixed

  • The Settings page's form no longer squeezes its switches. Each row is now a two-column grid whose second track is a fixed 280px control column: the label and the control share one line, the hint sits under the label, and a select ellipsizes instead of wrapping inside its own height. Before, a long hint's max-content width made the flex row shrink the control, so both connection switches drew about 120px wide with two- and three-line labels detached from their rows — the misalignment the form showed in both languages. The connection rows traded the mixed "attach 共享" / "Attach sharing" label for "共享方式" / "Sharing", every hint was shortened, the control stacks under its label below 720px, and a select now draws the shell's focus ring. The text fields also line up with the selects now: the Input primitive's wrapper adds padding and a border outside its width, so the form's border-box declaration makes a 280px text field exactly as wide and high as a 280px select instead of 297×33. The injected rules are also rewritten in place rather than skipped when the style tag already exists, because DSH can hot-swap a changed client bundle into a live page and the new markup used to draw with the previous bundle's rules. test/inspector.mjs adds a structural check that every row keeps its control in that column, and both READMEs' settings-page section now lists the connection switches where they belong.

中文

新增

  • 插件页现在能检测自身的更新:页面右上、卸载按钮旁多出一个检查更新控件,它通过插件市场的公开更新 API(dshmarket 的 UPDATE-API-V1)查询 npm 上的最新版本,有新版就变成更新到 vX.Y.Z,随后展示已接受安装的进度与结果——需要刷新界面(refreshRequired)、需要重启 DSH、被 AGENTS_RUNNING 之类的理由拒绝,或是发布未满发布年龄限制时给出强制更新重试。端点、响应包络与重启归属都从 capabilities 回答里发现;没有挂载插件市场的 Host 不会出现这个控件(lib/client.js;test/inspector.mjs 新增 13 项离线检查,检查数变为 63)。

修复

  • 配置页的表单不再挤压控件。每一行现在是两列网格,右列固定为 280px 的控件列:标签与控件同一行,说明在标签下方,选项文字放不下时省略而不是在控件自身高度里换行。以前长说明的 max-content 宽度会让 flex 行把控件压小,两个连接开关画出来只有约 120px 宽、标签折成两三行并与所在行脱开——中英两种界面都是这个错位。连接相关的行把混排的「attach 共享」/「Attach sharing」改成「共享方式」/「Sharing」,各项说明同步精简;窗口窄于 720px 时控件落到标签下方占满整行;选项获得焦点时会画 shell 自己的 focus ring。文本框现在也和选项框对齐:Input 组件的包裹层把内边距和边框加在宽度之外,表单的 border-box 让它和同列的 280px 选项框一样宽、一样高,而不再是 297×33。注入的规则也改成在已有 <style> 上原地重写而不是直接跳过——DSH 会把改动过的 client bundle 热替换进正在运行的页面,旧标记曾因此继续套用上一版 bundle 的规则。test/inspector.mjs 新增一项结构检查,保证每一行都把控件放在这个固定列里;两份 README 的配置页一节也补上了连接方式这两个字段。

v0.8.0

Choose a tag to compare

@github-actions github-actions released this 23 Oct 14:45

Added

  • The Settings page offers the connection switches, not only Jev's: mode (launch starts a browser this Session owns, attach drives the one you already use) and, once the mode is attach, attachSharing (exclusive keeps it for the first live Session, shared lets every Session drive it in its own tab). Both are live fields in lib/config.js, so the Loader commits an edit into the reference the running plugin holds and the next browser_open honours it — a browser a Session has already opened keeps the mode it was opened under, so flipping the switch never reaches back into a running browser. The sharing row states its stored value on a locked control while the mode launches its own browser, and moving the mode back to launch carries the attachSharing: "exclusive" reset in the same write, because the schema refuses shared with launch and a form that wrote one half alone would hand the person a refusal instead of the change they asked for (lib/client.js; 49 checks in test/inspector.mjs, and the form-field set in test/plugin.mjs now names both).
  • test/plugin.mjs opens a local rating grid through the plugin and checks that the table offers all twelve one-character cells, that clicking one reaches the page, and that a lone character stays text — the bundled engine revision, end to end.
  • test/test_bridge.py: a value that cannot cross by value is a js_error carrying the way out (JSON.stringify), and a non-finite timeout_ms answers instead of ending the sidecar.
  • The browser_eval regression checks now test what they claim: the object case sends an object rather than JSON.stringify of one (which only exercised the string branch), "no observation" is proven by the next read being exactly +1 rather than by two numbers a consumed observation would also satisfy, and window is checked to come back as text.

Changed

  • The bundled engine is jev-ultrafast 0.1.1 (revision 50b319f): a rating grid's one-character cells — no role, no tabindex, no href, in a cluster of identical cells — are now CLICK targets, while a lone character on the page stays text. The demo fixture's table is unchanged (15 actions, 9 clickable), so the pass adds no noise to a page without cells. The engine's own guard checks and its test suite cover it, and bin/vendor_engine.py check proves the wheel holds that revision file for file.
  • Both READMEs now say the remote-debugging prompt is asked per connection, not once per plugin: every tool reuses the Session's one connection, and a browser_close followed by a new browser_open starts a new daemon, so attach mode asks once again on that next connection.

Fixed

  • A launch no longer fails on a machine whose proxy does not exclude 127.0.0.1. Waiting for the browser's DevTools endpoint reads http://127.0.0.1:<port>/json/version with urllib, which applies the machine's proxy settings, so a proxy answering that request itself made a browser that had started perfectly well fail every browser_open as "did not open a DevTools endpoint within 25s" — for 25 seconds, on every attempt, while the Session's profile directory showed the browser up and writing to it. The probe is a loopback request and now goes through an opener with no proxy at all, the way discover_local_browser already reaches its endpoint over a raw socket (sidecar/bridge.py).
  • A failed launch now says what it can instead of only how long it waited: the executable, the profile, the port, the port the profile recorded in DevToolsActivePort, and the last lines the browser printed. Its stdout and stderr used to go to DEVNULL, which is exactly where a refused launch states its reason (sidecar/bridge.py launch_diagnosis; 5 offline checks in test/test_bridge.py, including the proxy that answers for a listening browser).
  • browser_eval no longer turns a value that cannot cross by value — window, a cyclic object, a chain over Chrome's limit — into a failed tool call. Chrome answers those with a protocol error rather than exceptionDetails, and the sidecar now reports them as js_error carrying the way out (JSON.stringify). Any other protocol-level failure comes back as text too, because a failed call is what sends a model looking for another client.
  • A browser_eval that awaits a promise gets a request deadline that covers the expression's own bound instead of a plain call's requestTimeoutMs. A profile with a short request cap used to reject the call while the sidecar was still working, and the request behind it waited on that work.
  • A timeout_ms that JSON carries as 1e400 (infinity) is clamped like any other out-of-range value, instead of raising OverflowError past the request loop and ending the sidecar.

中文

新增

  • 配置页现在给出连接方式这一组,不再只有 Jev 的开关:mode(launch 由插件自己启动一个只属于本 Session 的浏览器,attach 驱动你已经在用的那一个),以及 mode 为 attach 时的 attachSharing(exclusive 把浏览器留给第一个活跃 Session,shared 让每个 Session 各开自己的标签页同时驱动)。两者在 lib/config.js 里都是 live 字段:Loader 会把改动提交进运行中插件持有的那个引用,下一次 browser_open 就按新值走——而一个 Session 已经打开的浏览器仍按它被打开时的模式继续,所以拨这个开关不会回头打断正在跑的浏览器。launch 模式下,共享那一行用一个锁定控件显示当前值(不弹菜单,schema 本来就会拒掉那一组),而把模式拨回 launch 时会在同一次写入里带上 attachSharing: "exclusive" 的重置——否则只写一半,人拿到的是拒绝而不是他想要的改动(lib/client.js;test/inspector.mjs 49 项检查,test/plugin.mjs 的表单字段集合现在也列出了这两项)。
  • test/plugin.mjs 通过插件打开一个本地评分表,检查动作表给出全部 12 个单字符格子、点其中一格真的到达页面、以及孤立的单字符仍然是文本——用随包的那一版引擎端到端验证。
  • test/test_bridge.py:无法按值返回的值报成带提示的 js_error(提示里给出 JSON.stringify 这条出路);非有限 timeout_ms 会正常应答而不是结束 sidecar。
  • browser_eval 的回归检查现在真的在测它声称的东西:对象用例直接返回对象(而不是返回 JSON.stringify 的字符串,那只走到字符串分支);“不产生观测”用下一次读取正好 +1 来证明,而不是拿两个“消耗了观测也照样成立”的数字比大小;window 会被检查成按文本返回。

变更

  • 随包引擎升级到 jev-ultrafast 0.1.1(revision 50b319f):评分格(无 role、无 tabindex、无 href、单字符、成组出现的格子)现在是 CLICK 目标,而页面上孤零零的一个字符仍然只是文本。演示页面的动作表不变(15 个动作、9 个可点),所以对没有这类格子的页面不增加噪声。引擎自己的守卫检查与测试套件覆盖了它,bin/vendor_engine.py check 逐文件证明 wheel 就是那个 revision。
  • 中英两份 README 改成:授权是按连接要一次,不是整个插件只弹一次——所有工具复用本 Session 的那一条连接,而 browser_close 之后再 browser_open 会起一个新的 daemon,attach 模式下那一次新连接会再问一次。

修复

  • 本机代理没有排除 127.0.0.1 的机器上,启动不再失败。等待浏览器 DevTools 端点的那次探测用 urllib 读 http://127.0.0.1:<port>/json/version,而 urllib 会套用本机代理设置;于是替它作答的代理让一个明明已经正常启动的浏览器,每一次 browser_open 都以「25 秒内没有打开 DevTools 端点」失败——25 秒、每一次都是,而该 Session 的 profile 目录里能看见浏览器起来并在写盘。这次探测是回环请求,现在改走完全不经过代理的 opener,和 discover_local_browser 早就用裸 socket 取端点是一个道理(sidecar/bridge.py)。
  • 启动失败现在会说出它能说的,而不只是等了多久:启动的是哪个可执行文件、哪个 profile、哪个端口、profile 的 DevToolsActivePort 里记录的端口,以及浏览器自己最后打印的几行。它的 stdout/stderr 以前直接进了 DEVNULL,而拒绝启动的原因恰好写在那里(sidecar/bridge.py 的 launch_diagnosis;test/test_bridge.py 新增 5 项离线检查,其中包括「代理替一个正在监听的浏览器作答」那一条)。
  • browser_eval 不再把“无法按值返回”的结果(window、循环引用对象、超过 Chrome 链长上限的值)变成失败的调用。Chrome 对这类情况返回的是协议错误而不是 exceptionDetails,sidecar 现在把它报成 js_error 并带上出路(JSON.stringify)。其他协议级失败也按文本返回,因为失败的调用正是把模型推向“换个客户端再试”的原因。
  • 会 await Promise 的 browser_eval 现在拿到的是覆盖表达式自身上限的请求期限,而不是普通调用的 requestTimeoutMs。profile 把请求上限调小时,以前会在 sidecar 还在干活时就拒绝这次调用,排在它后面的请求也跟着等。
  • JSON 里的 1e400(无穷大)作为 timeout_ms 时,现在和任何越界值一样被钳制,而不是抛 OverflowError 越过请求循环、把 sidecar 结束掉。

v0.7.1

Choose a tag to compare

@github-actions github-actions released this 23 Oct 09:48

Added

  • browser_eval: one JavaScript expression evaluated on the page this Session owns, answered as text — a string as itself, every other value as JSON, a DOM node or function by its description, capped at 12000 characters. It exists because a model that needed a programmatic read had no supported way to get one, so it started its own CDP client; that is what turned Chrome's per-connection "Allow remote debugging?" consent into a stack of prompts. It runs on the Session's own connection, gets no user gesture, bounds an awaited promise (30 s by default, at most 120 s), reports a thrown expression as text instead of as a failed call, and produces no observation: the next browser_act still belongs to the observation the page was last read in. Config key allowEval (default true) withdraws it, restoring a surface where model output can never become code.
  • browser_doctor in mode: attach prints a Connection: line — one CDP client for this Session, because Chrome 144+ asks once per connection, so a second client is a second prompt. The doctor is the tool a person already calls first when a browser behaves oddly.
  • 10 checks in test/plugin.mjs (4 for the guidance rule, 6 for browser_eval: the value, no observation, digits as digits, JSON for an object, a throw as text, and a fresh observation after an evaluation) and 5 offline checks in test/test_bridge.py (the value and its CDP parameters, JSON/capping/DOM description, a thrown expression as js_error rather than a lost page, the timeout clamp, and a lone surrogate that must come back encodable instead of ending the sidecar). The attach-to-your-Chrome group gained 3: the doctor's Connection: line, allowEval: false withdrawing the tool, and the guarded tools staying.

Changed

  • The browser guidance now states the one-connection rule: every browser tool shares the single CDP connection this Session's daemon holds; a second client (a raw websocket to Chrome's DevTools port, a puppeteer/playwright script, another browser-harness daemon) raises another Chrome prompt and races the page; if the prompt appears, approve that exact sheet once and never retry, because a retry drops it and raises a new one. With allowEval on the guidance names browser_eval as the supported way to do programmatic work; with it off it says the table is all there is.
  • Both READMEs: the tool table, the configuration table, the attach section, the "targets come from the observation" claim and the limits section document browser_eval, the allowEval switch and the per-connection prompt rule, so the project's first principle is stated as having exactly one named, switchable exception.

Fixed

  • A model that needs a programmatic read no longer has to leave the plugin. The supported path is one connection, so Chrome raises its one "Allow remote debugging?" prompt instead of one per short-lived client; the plugin itself never opened a second client, and the prompt storm in the reported session came from an agent's ad-hoc CDP scripts after a delegated task was interrupted.

中文

新增

  • browser_eval:在本 Session 自己的页面里执行一个 JavaScript 表达式,按文本返回结果——字符串原样返回,其他值按 JSON 返回,DOM 节点或函数返回它的描述,最长 12000 字符。加它的原因是:模型需要程序化读取时没有受支持的路子,于是自己去开 CDP 客户端;而 Chrome 是按连接弹「要允许远程调试吗?」,于是一次授权变成了一摞弹窗。它跑在本 Session 已有的连接上,不拿 user gesture,等待 Promise 有上限(默认 30 秒,最多 120 秒),表达式抛错按文本报告而不是当成工具调用失败,并且不产生观测:下一次 browser_act 仍然属于最后一次读页面时的那个观测。配置项 allowEval(默认 true)可以收回它,回到"模型输出永远不会变成代码"的表面。
  • mode: attach 下 browser_doctor 多一行 Connection::本 Session 只有一条 CDP 连接,Chrome 144+ 按连接授权,所以第二个客户端就是第二张弹窗。浏览器行为反常时,医生本来就是人会先问的工具。
  • test/plugin.mjs 新增 10 项检查(4 项提示词规则、6 项 browser_eval:返回值、不产生观测、数字按数字、对象按 JSON、抛错按文本、求值之后重新读页面是新观测);test/test_bridge.py 新增 5 项离线检查(返回值与它带的 CDP 参数、JSON/截断/DOM 描述、抛错归为 js_error 而不是丢页面、超时钳制、以及孤立代理项必须变成可写文本而不是让 sidecar 结束)。"接你的 Chrome"那一组另加 3 项:医生的 Connection: 行、allowEval: false 收回工具、受保护工具仍在。

变更

  • 浏览器提示词里写明"一条连接"规则:所有浏览器工具共用本 Session daemon 持有的那条 CDP 连接;第二个客户端(直连 Chrome DevTools 端口的裸 websocket、puppeteer/playwright 脚本、另一个 browser-harness daemon)会再弹一张、并且和对页面形成两个驱动者;万一弹窗出现,就点那张、不要重试——重试会把它关掉再弹一张。allowEval 开着时提示词把 browser_eval 指为做程序化工作的正路;关掉时则说明表就是全部。
  • 中英两份 README:工具表、配置表、attach 章节、"目标来自观测而不是模型的想象"那条优势、以及局限章节,都写清了 browser_eval、allowEval 开关和按连接授权的规则,于是本项目的第一原则被表述成"有且只有一个写明了的、可开关的例外"。

修复

  • 需要程序化读取的模型不必再离开插件。正路只有一条连接,Chrome 只弹一次「要允许远程调试吗?」,而不是每个短连接一次;插件自己从不曾开第二个客户端,上报那次会话里的弹窗风暴来自被中断的委派任务之后 agent 手搓的 CDP 脚本。

v0.7.0

Choose a tag to compare

@github-actions github-actions released this 18 Oct 06:16

Added

  • attachSharing: exclusive (the default) or shared. In mode: attach, shared withdraws the one-Session reservation, so every live Session may drive the same external browser — each through its own daemon and its own tab — instead of the second one being refused. Sharing changes nothing about letting go: closing one Session's browser closes that Session's tab and stops its daemon, never the browser the others are still using (test/test_bridge.py pins that down). shared with mode: launch is refused when the profile loads, because a launched browser already belongs to one Session.
  • Sessions.attachHolders, the number of live Sessions holding the attached browser. A Session holds it from its first browser call — the reservation is taken before the engine is asked, which is what makes the refusal the second Session reads the one that matters — so this is "who holds it", not "who has a page open". browser_doctor prints it in attach mode (attach sharing shared (2 live)), so "why was my other Session refused the browser" is answered by the tool a person already calls first.
  • 9 offline checks for the answers sharing can give (test/plugin.mjs): sharing withdraws the refusal and reaches the engine, the default stays exclusive, asking to share outside attach mode is refused, and browser_close says what it does not close. The exclusivity checks now cover both halves of a reservation — the second Session is refused, and closing the holder frees it for the next one (test/plugin.mjs attachExclusivity).

Changed

  • The attach refusal now names the third way out — attachSharing "shared" — beside waiting for the holder to close its browser and giving each Session its own browser with mode: "launch".
  • browser_close in mode: attach describes what it actually closes — this Session's tab and its daemon, never the attached browser — and its result says the same, instead of the launch-mode wording that promised the browser was stopped.

Fixed

  • A profile that exports BH_RUNTIME_DIR (or BH_TMP_DIR) without the engine's own …_SHARED=1 no longer collapses every Session's daemon into one name. The plugin starts one sidecar per Session in that directory, so it now marks the directory shared for them (lib/sidecar.js inheritedEnvironment); without that, the second Session found the first Session's daemon and either one closing stopped the daemon the other was driving (5 offline checks in test/plugin.mjs). An explicit …_SHARED=0 is overridden on purpose: the plugin is the caller that makes the directory shared, and a daemon an older version left at the bare bu name is simply no longer addressed.

中文

新增

  • attachSharing:exclusive(默认)或 shared。mode: attach 下设成 shared 就撤回"一次只留给一个 live Session"的保留:所有 live Session 都能驱动同一个外部浏览器,各用各自的 daemon 与标签页,第二个会话不再被拒。共享不改变"放手"的方式——关掉某个会话的浏览器只关它自己的标签页、只停它自己的 daemon,不会关掉其他会话还在用的那个浏览器(test/test_bridge.py 有专项断言)。mode: launch 配 shared 会在 profile 加载时被拒绝:自起的浏览器本来就属于一个 Session。
  • Sessions.attachHolders:正持有这个附加浏览器的 live Session 数量。会话在它第一次调用浏览器工具时就持有——保留发生在问引擎之前,这也正是第二个会话读到的那条拒绝信息有意义的原因——所以这个数字是"谁占着",不是"谁开着页面"。attach 模式下 browser_doctor 会打印它(attach sharing shared (2 live)),于是"我另一个会话为什么被拒"用那个本来就会先问的工具就能答。
  • 针对共享两种结果的 9 项离线检查(test/plugin.mjs):共享撤回拒绝并走到引擎检查、默认仍是独占、在 attach 之外要求共享会被拒绝,以及 browser_close 要讲清自己不关什么。独占检查现在覆盖保留的两半:第二个会话被拒,以及持有者关闭后下一个会话能拿到(test/plugin.mjs 的 attachExclusivity)。

变更

  • attach 的拒绝信息补上第三条出路——attachSharing "shared"——与"等持有者关掉浏览器""用 mode: "launch" 让每个会话各有浏览器"并列。
  • mode: attach 下 browser_close 的描述与结果都改成它真正做的事:关掉本 Session 的标签页与 daemon,不关接来的那个浏览器;不再沿用 launch 模式那句"浏览器已停止"。

修复

  • profile 里导出了 BH_RUNTIME_DIR(或 BH_TMP_DIR)却没带引擎自己的 …_SHARED=1 时,不再把所有 Session 的 daemon 压成同一个名字。插件本来就会在这个目录里为每个 Session 起一个 sidecar,所以现在由它替它们标上"目录是共享的"(lib/sidecar.js 的 inheritedEnvironment);没有这一步时,第二个 Session 会找到第一个 Session 的 daemon,任何一方关闭都会把对方正在驱动的 daemon 停掉(test/plugin.mjs 另有 5 项检查)。运营者显式写的 …_SHARED=0 会被覆盖,这是有意的:让这个目录变成"共享"的调用方就是插件;而旧版本遗留在裸 bu 名下的 daemon 只是不再被寻址。

v0.6.3

Choose a tag to compare

@github-actions github-actions released this 18 Oct 03:34

Added

  • CHANGELOG.zh-CN.md: the changelog in Chinese, every release from 0.1.0 to 0.6.3, translated section by section against the English file and shipped in the npm package beside the two READMEs.
  • The GitHub Release body is now bilingual: this version's English section, then the Chinese one under a **中文** heading. The plugin market shows the release body as a plugin's update notes, so the notes it shows for this package are readable in both languages.

Changed

  • release.yml builds the release body from the two changelogs instead of GitHub's generated notes, which list pull requests only and left every body as one compare line (the first step of this, 34126ad, used the English section alone); a version with no changelog section still falls back to the generated notes.
  • bin/check-package.mjs requires CHANGELOG.zh-CN.md in the published tarball, and both READMEs' release steps now say to write the entry in both files.

中文

新增

  • CHANGELOG.zh-CN.md:中文版 changelog,覆盖 0.1.0 到 0.6.3 的每个版本,逐段对照英文版翻译,并随 npm 包与两个 README 一起发布。
  • GitHub Release 正文改为双语:先是本版本的英文段落,再是 **中文** 标题下的中文段落。插件市场把 Release 正文当作插件的「版本说明」展示,所以本包在市场里的说明中英文都能读。

变更

  • release.yml 改为从两份 changelog 生成 Release 正文,不再用 GitHub 自动生成的说明(它只列 PR,而本仓库直接从 main 发版、没有 PR,所以正文一直只有一行 compare 链接;34126ad 是这条修复的第一步,只用了英文段);某版本没写 changelog 段落时仍退回自动说明。
  • bin/check-package.mjs 要求发布的 tarball 里包含 CHANGELOG.zh-CN.md;两个 README 的发版步骤都改成要在两份 changelog 里各写一条。

v0.6.2

Choose a tag to compare

@github-actions github-actions released this 17 Oct 14:06

Added

  • A live progress feed from the delegated browser subagent into the conversation that owns it: lib/progress.js (ProgressFeed) turns each browser step the plugin already records (Sessions.observed() / noteAction()) into a two-line status message, sent as an agent-message from the child, so a conversation can end its turn instead of blocking in browser_task_status with wait: true to watch the work.
  • Config key progress (boolean, default true): whether the feed pushes anything at all, read again on every step; resolveConfig refuses anything but true or false, so a truthy non-boolean cannot turn the stream off in silence.
  • Config key progressIntervalMs (number, default 30000): the shortest gap between two progress messages, coalesced per child in a window floored at PROGRESS_MIN_MS (1000 ms) and held inside what setTimeout carries; the first step of a window reports at once, a step inside it is reported when the window closes, and resolveConfig refuses a value that is not a finite number >= 0.
  • Sessions.onStep(listener), called with the owning Agent after every recorded step, so the browser tools stay unaware that anything listens; a listener that throws is logged and never fails the tool that took the step (a logger that throws too costs only the report).
  • test/progress.mjs: adversarial coverage of the feed (exported defaults, the exact message text, coalescing, the drop rules, a refused delivery, the interval boundaries and the listener guard, plus integration through the real plugin and a real browser), wired into npm test and npm run check.

Changed

  • The browser_task receipt and the persistent-subagent guidance now say the subagent reports progress on its own — short status messages that need no reply and are not its result — and describe browser_task_status as a snapshot on request whose wait: true is a last resort; the browser_task and browser_task_status tool descriptions and the wait parameter say the same.
  • browser_task_status wording for a wait the subagent ended by writing: "sent you a message (progress or a question)".
  • Unloading the plugin releases the feed (pending windows are cleared and pushes in flight are aborted) and subagent/end forgets a settled child's state, so a conversation this plugin no longer serves is not woken by a stale status.
  • package.json: lib/progress.js added to the published files list, and node test/progress.mjs added to the test and check scripts; test/delegation.mjs also drives the feed end to end (one message for a step, a step inside the window coalesced, the next window reporting the observation and the action taken there).
  • README.md and README.zh-CN.md: the tools table, the delegation notes, the configuration table and the architecture diagram document the feed, its two-line shape and the progress / progressIntervalMs keys.
  • The vendored engine wheel vendor/jev_ultrafast-0.1.0-py3-none-any.whl was rebuilt from jev-ultrafast 0097710, vendor/jev-ultrafast.json now pins that revision, and uv.lock re-pins the wheel hash.

Fixed

  • A tab the plugin owns is now laid out in the browser window it was opened in instead of a pinned 1120x780 emulated viewport: the re-vendored wheel carries jev-ultrafast 0097710, which leaves an owned tab unpinned when the browser has a window to take a size from, still gives headless a 1120x780 viewport, and honours JEV_VIEWPORT=WIDTHxHEIGHT for a caller that wants a fixed frame.

中文

新增

  • 一条从被委派的浏览器子 agent 推回它所属对话的实时进度推送:lib/progress.js(ProgressFeed)把插件本来就记录的每一步浏览器操作(Sessions.observed() / noteAction())变成一条两行状态消息,以子 agent 名义作为 agent-message 发出,于是对话可以结束本轮,而不必在 browser_task_status 里用 wait: true 阻塞着看它干活。
  • 配置项 progress(布尔,默认 true):这条推送到底推不推东西,每一步都会重新读一次;resolveConfig 只接受 true 或 false,所以一个“真值”的非布尔值没法悄悄把推送关掉。
  • 配置项 progressIntervalMs(数字,默认 30000):两条进度消息之间最短的间隔,按子 agent 在窗口里合并,窗口下限是 PROGRESS_MIN_MS(1000 ms),并保持在 setTimeout 能承载的范围内;窗口里的第一步立即上报,窗口内后续的步在窗口关闭时上报,而 resolveConfig 拒绝任何不是有限数字 >= 0 的值。
  • Sessions.onStep(listener),在每一步被记录后带着所属 Agent 调用,所以浏览器工具始终不知道有人在监听;抛错的监听器只会被记进日志,绝不会让走这一步的工具失败(连日志器也抛错,代价也只是这份上报)。
  • test/progress.mjs:对这条推送的对抗性覆盖(导出的默认值、确切的消息文本、合并、丢弃规则、一次被拒绝的投递、间隔边界与监听器守卫,以及经由真实插件和真实浏览器的集成),并接入 npm test 与 npm run check。

变更

  • browser_task 的回执和常驻子 agent 的指引现在写明:子 agent 会自己推进度——那是简短的状态消息,不需要回复,也不是它的结论;并把 browser_task_status 说成按需取一次的快照,其中的 wait: true 是最后的办法;browser_task 与 browser_task_status 的工具描述和 wait 参数也是同样的说法。
  • browser_task_status 里描述"子 agent 用一条消息结束的等待"的措辞改成 sent you a message (progress or a question)(“给你发了一条消息:进度或提问”):这句是给模型看的,仍是英文原文。
  • 卸载插件时会释放这条推送(待处理的窗口被清掉,在途的推送被中止),subagent/end 会忘掉一个已结算子 agent 的状态,于是插件已不再服务的对话不会被一条过期的状态叫醒。
  • package.json:把 lib/progress.js 加进发布的 files 列表,把 node test/progress.mjs 加进 test 与 check 脚本;test/delegation.mjs 也端到端驱动这条推送(一步一条消息,窗口内的步被合并,下一个窗口上报那次观测与在那里执行的动作)。
  • README.md 与 README.zh-CN.md:工具表、委派说明、配置表和架构图都写明了这条推送、它的两行形状以及 progress / progressIntervalMs 两项。
  • 随包的引擎 wheel vendor/jev_ultrafast-0.1.0-py3-none-any.whl 改为由 jev-ultrafast 0097710 重新构建,vendor/jev-ultrafast.json 现在固定到该 revision,uv.lock 重新锁定这个 wheel 的哈希。

修复

  • 插件自己持有的标签页现在按它被打开时所在的浏览器窗口布局,而不是固定成 1120x780 的模拟视口:重新随包的 wheel 带着 jev-ultrafast 0097710,浏览器有窗口可量尺寸时就不再把自有标签页钉住,无窗口时仍给 1120x780 视口,并尊重 JEV_VIEWPORT=WIDTHxHEIGHT,给想要固定画面的调用方用。

v0.6.1

Choose a tag to compare

@github-actions github-actions released this 16 Oct 14:26

Fixed

  • The settings form's Jev key row now asks for jev.typesafe.apiKey itself — one write-only password input — instead of jev.typesafe.apiKeyEnv, whose shape refused a key pasted by someone who had it in hand; the Host strips role('secret') fields from every form response (so the field always reads blank), a blank draft writes nothing (the stored key survives), and an accepted write answers "Saved". apiKeyEnv stays supported for a profile patch that would rather name a stored credential, but it is no longer a live form field and its refusal now says to put the key in apiKey.

中文

修复

  • 设置表单里的 Jev 密钥那一行现在要的就是 jev.typesafe.apiKey 本身——一个只写不读的密码输入框——而不再是 jev.typesafe.apiKeyEnv,后者那种形状会把一个手里明明拿着密钥的人粘进来的 key 拒绝掉;Host 会把 role('secret') 字段从每个表单响应里剥掉(所以该字段读出来永远是空的),空白草稿不写入任何东西(已存的 key 保留下来),写入被接受时回答“已写入”。apiKeyEnv 仍留给“宁可指名一份已存凭据”的 profile patch,但它不再是在用的表单字段,它的拒绝提示现在会说把 key 写进 apiKey。

v0.6.0

Choose a tag to compare

@github-actions github-actions released this 16 Oct 12:16

Added

  • jev.decider (typesafe by default, chat as the alternative): with chat the sidecar answers the loop's decisions from the text model, so browser_goal and an intent-bearing browser_act need no Jev key; the sidecar serves a loopback chat-decision endpoint for a single decision or goal run.

Changed

  • Jev is on whenever the plugin is: jev.enabled now defaults to true and is no longer a .volatile() switch, the form's one volatile setting is jev.decider (who answers, not whether Jev runs), and an empty typesafe.apiKey spends the main conversation route's own key.
  • The Jev settings form is a single decider choice plus the Jev endpoint and key fields, and its labels, hints and refusals follow the shell locale instead of a hard-coded language (locale/en.json, locale/zh.json).
  • jev.textModel is no longer a form field and defaults to reasoning: 'thinking-disabled'; the vendored Jev wheel and the benchmark docs and illustrations were refreshed to match.

中文

新增

  • jev.decider(默认 typesafe,备选 chat):用 chat 时,sidecar 由文本模型回答环路里的决策,于是 browser_goal 和带 intent 的 browser_act 都不需要 Jev key;sidecar 会为一次决策或一次目标运行在本地提供一个 chat 决策端点。

变更

  • 插件在,Jev 就在:jev.enabled 现在默认 true,且不再是 .volatile() 开关,表单里唯一的 volatile 设置是 jev.decider(决定谁来回答,而不是 Jev 跑不跑),typesafe.apiKey 留空就直接花主会话路由自己的 key。
  • Jev 设置表单就是一个决策者选项,加上 Jev 端点与 key 字段;它的标签、提示和拒绝文案跟随 shell 自己的 locale,而不是写死一种语言(locale/en.json、locale/zh.json)。
  • jev.textModel 不再是表单字段,默认 reasoning: 'thinking-disabled';随包的 Jev wheel 以及基准文档和配图都跟着刷新了。

v0.5.1

Choose a tag to compare

@github-actions github-actions released this 02 Oct 11:49

Changed

  • The npm package is published as @ricardochen1996/dsh-browser-use: the manifest, the Cordis bundle row, the client module id and the form registration keys all carry the new name, while the internal identifier dsh-browser-use, the dsh-browser-use/inspector tab id, the /browser-use/ route, the log prefix and the profile config keys are unchanged.
  • The READMEs now say to remove the old plugin entry (@weichen96/dsh-browser-use) before adding this one, and record that the first release under the new name had to be published by hand, because npm only offers a package's trusted-publishing settings once the package exists; releases up to 0.5.0 stay installable under the old scope.
  • 0.5.1 is the first release published under the new scope and the first one released through release.yml; the plugin itself is unchanged from 0.5.0.

中文

变更

  • npm 包以 @ricardochen1996/dsh-browser-use 的名字发布:清单、Cordis bundle 行、客户端模块 id 和表单注册键都换成新名字,而内部标识 dsh-browser-use、dsh-browser-use/inspector 标签页 id、/browser-use/ 路由、日志前缀和 profile 配置项保持不变。
  • 两处 README 现在都说:要先移除旧的插件条目(@weichen96/dsh-browser-use)再添加这一个;并记下新名字下的第一个版本只能手动发布,因为 npm 的 trusted publishing 设置要等包存在之后才提供;到 0.5.0 为止的版本仍在旧 scope 下可以安装。
  • 0.5.1 是第一个在新 scope 下发布的版本,也是第一个通过 release.yml 发布的版本;插件本身与 0.5.0 相比没有变化。