Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
36e0e56
fix(web): improve session isolation and workbar interactions
testikun Sep 20, 2026
6c58e98
docs: link Web UX findings to issue 597 and PR 598
testikun Sep 20, 2026
1d9607b
fix(web): unblock first-use controls and defer search setup
testikun Sep 20, 2026
4d229e5
fix(web): enable native settings and improve browser and Git views
testikun Sep 21, 2026
c781376
fix(web): preserve model drafts and remove browser input stalls
testikun Sep 21, 2026
ece3e42
fix(web): reconcile settings feedback and preserve pointer state
testikun Sep 21, 2026
d9568c4
merge: integrate current main for web experience iteration
testikun Sep 22, 2026
fbf15d2
fix(web): polish workbar, settings and execution feedback
testikun Sep 22, 2026
2f78cf3
fix(web): restore history and isolate background session progress
testikun Sep 22, 2026
4e9ba87
fix(web): retain reading state and browser address drafts
testikun Sep 22, 2026
6126e38
docs: record web CI results and network comparison
testikun Sep 22, 2026
0b5a0f2
fix(web): preserve bounded Chromium startup diagnostics
testikun Sep 22, 2026
4480b8d
fix(web): await browser closure before removing profiles
testikun Sep 22, 2026
13465ad
test(web): respect React and platform process lifecycles
testikun Sep 22, 2026
6fcb100
Merge main with native Web interactions and UX fixes
testikun Sep 22, 2026
0bc3470
Merge main setup recovery and workspace identity fixes
testikun Sep 22, 2026
81d4c67
fix(web): preserve Git rename details and comparison identities
testikun Sep 23, 2026
250731f
ci: provide a private D-Bus session for browser tests
testikun Sep 23, 2026
94059b5
fix(web): show turn-scoped changes and recover full messages
testikun Sep 23, 2026
f0e85cd
Show native queued follow-ups beside Web composer
testikun Sep 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -189,9 +189,19 @@ jobs:
bun-version: 1.3.14
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Install Chromium
run: bunx playwright install --with-deps chromium
- run: bun run test:web:e2e
- name: Install Chromium and D-Bus
run: |
bunx playwright install --with-deps chromium
sudo apt-get install --no-install-recommends -y dbus-daemon
- name: Verify isolated Chromium cold starts
timeout-minutes: 2
run: dbus-run-session -- node --experimental-strip-types tests/web/browser-cold-start-smoke.mjs
env:
OPENPI_CHROME_PATH: /opt/google/chrome/chrome
- run: dbus-run-session -- bun run test:web:e2e
env:
# The runner's installed Chrome has Ubuntu's native sandbox profile.
OPENPI_CHROME_PATH: /opt/google/chrome/chrome
- name: Upload Playwright failure artifacts
if: failure()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
Expand Down
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -569,7 +569,7 @@ pi install npm:pi-intercom

### 独立 Web 工作台

Web runtime 不嵌入交互式终端 Session。它由独立进程创建自己的 Pi `AgentSessionRuntime`、独立 `~/.pi/agent/web-sessions` 持久化目录和生命周期;浏览器发送消息、新建 Session 或切换工作区,不会写入或切换任何已经运行的终端 Pi Session,Web Session 也不会出现在终端的默认 Session 列表中。在侧栏选择 Session 会把它激活为 Web 进程的当前 Pi Session;Prompt 只会投递到请求时仍匹配的活动 Web Session。独立的只读历史浏览不属于首版范围。
Web runtime 不嵌入交互式终端 Session。它由独立进程创建自己的 Pi `AgentSessionRuntime`、独立 `~/.pi/agent/web-sessions` 持久化目录和生命周期;浏览器发送消息、新建 Session 或切换工作区,不会写入或切换任何已经运行的终端 Pi Session,Web Session 也不会出现在终端的默认 Session 列表中。在侧栏选择 Session 会把它激活为 Web 进程的当前 Pi Session;Prompt 只会投递到请求时仍匹配的活动 Web Session。其他页面切换活动会话时,本页保留正在看的会话及其后台进度;需要继续对话或使用交互工具时,点击“切换到此会话”。读取与刷新不会自动抢占活动会话。

同一 Pi agent 目录一次只允许一个 Web Host 持有该 Session/元数据目录。第二个 `openpi web` 会明确拒绝启动;正常关停会先排空共享目录变更再释放租约,进程崩溃后仅在确认原 owner 的 PID 与进程启动身份不再匹配时恢复。一个 Host 可在侧栏管理多个工作区,因此不需要为每个仓库启动一个进程。

Expand All @@ -590,6 +590,19 @@ openpi web /path/to/repo # 指定初始工作区

Web 可以在选择工作区之前预选可用模型。选择仅保留在当前页面,创建会话后确认模型生效再发送第一条消息;模型不可用时会提示并阻止发送,不会自动换成默认模型。打开已有会话时使用该会话的模型。

Web 设置页可以添加或编辑自定义模型、保存服务商 API Key。模型写入 Pi 原生 `models.json`,密钥通过 Pi 登录接口写入原生凭据存储,已有密钥不会回显或进入模型对话。写入要求活动会话空闲;外部配置发生变化时需刷新后重试。OAuth 和需要额外认证字段的服务商仍使用 Pi 原生登录。技能、插件、子代理及 OpenPI 自有偏好的 Web 表单统一提交到 `/openpi-setup`,进度与确认留在会话中;提交回执不代表配置已保存。

设置中的模型树直接选择编辑对象,同一会话的未保存模型草稿会保留。窄屏设置使用带文字的分类选择器;聊天宽度和字号支持恢复默认值。配置请求在对话中显示原始操作及后续结果,运行期间暂停再次应用,成功与否以原生配置结果为准。

输入 `/` 可查看原生发现的命令及不可用原因。`/openpi-setup` 使用原生配置回合;无参数的 `/ps`、`/lg`、`/subagents`、`/btw` 打开对应 Web 面板,不发送模型请求。这些面板快捷命令不接收参数或图片,带参时保留输入并提示。`/usage` 使用原生命令,在聊天中显示查询结果。运行中的回合显示“已处理”时间,结束后显示“用时”;时间从 Pi 实际开始执行计算,并随原生 Session 保存。没有可靠耗时记录的旧回合不推算补值。

输入框支持直接粘贴受支持的图片和混合文字,读取期间保留发送等待状态。生成文件中的 PNG、JPEG、GIF、WebP 可在已有文件授权范围内预览(上限 20 MiB);SVG 与 HTML 不作为图片执行。Git、文件和子代理面板隐藏时会减少自动读取,重新打开时恢复更新。

长会话可向上加载更早的消息,通常按最多 20 个用户回合取页,同时保留 250 条/2 MiB 上限;单个过大的回合仍可分段找回。阅读窗口上限为 1000 条/8 MiB。加载和流式追加保持阅读位置;发送新消息或点击“跳至最新”返回当前尾部。单条超长用户或助手正文可按原生条目 ID 显式加载完整内容,每次最多读取 32,000 个字符;工具输出仍保持有界预览。运行中有草稿时同时提供发送和停止按钮,排队数来自 Pi;已接收不表示已经执行完成。

变更面板默认展示 Git 未暂存变更,也可切换到暂存、分支或会话基线;输入框不再显示整个工作区的累计变更文件。新 Web 回合在对话中展示该轮期间的文件变化,审阅读取随 Pi Session 保存的有界 diff,不会用当前工作树冒充历史结果。此比较不能区分同一时间其他进程的改动;非 Git 工作区、过大的初始变更或超出记录上限时会标明无法验证或部分结果,旧回合不回填。手动变更面板的列表与逐文件 diff 分开加载,大型未跟踪文件不会阻止读取整个工作区;达到显示限额会标注截断。会话基线仍是有容量限制的附加视图,不能替代 Git。跨 worktree 的原生编辑记录可以在“生成文件”中查看;读取工作区外的文件需点击“只读打开此文件”,仅授权该文件,不放宽整个目录。

内嵌浏览器使用本机 Chromium CDP 的 PNG screencast 推送,根据面板大小和屏幕像素密度调整,最多保留最新待显示帧。它不是目标页面 iframe,也不提供桌面浏览器全部功能;复杂原生弹窗、下载或系统集成仍可通过“在浏览器中打开”使用外部浏览器。
在 Plan/Setup 原有工具范围内,模型调用 `ask_user` 时,发起任务的 Web 标签页会显示结构化问题卡片:选择选项、添加补充说明或填写自己的答案,复核后才提交给正在等待的工具调用。关闭卡片不会提交草稿;留空的自定义答案表示要求澄清问题。刷新同一标签可恢复尚未过期的提问(未提交草稿不持久化),其他标签不能代答。提问最多等待 15 分钟,停止运行、切换 Session 或关闭 Host 会取消等待;它不替代原生权限审批,也不意味着任意终端自定义界面已支持 Web。

OpenPI 的 `/plan` 调研通过 `plan_ready` 成功提交计划后,Web 会在聊天区展示可收起、可复制的 Markdown 计划卡片,刷新后仍可查看。卡片展示的是工具返回的计划,不代表批准或开始实施;超出 Web 传输上限的结果会标明为预览。输入框上方的开关由现有 Plan 扩展切换当前 Session 的规划状态,不调用模型、不发送命令气泡,也不清空草稿;发送任务后才开始规划。首次发送后,输入框占位提示会说明“本次对话使用 Plan 模式”,刷新后保留,退出后恢复。任务运行期间不能切换模式,退出不代表批准或开始实施。手动 `/plan <目标>` 仍会直接开始规划,`/plan off` 仍可退出;Plan Ready 的实施确认仍需使用 TUI。
Expand Down
5 changes: 5 additions & 0 deletions SETUP.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ The terminal theme above remains Pi-owned. OpenPI Web has separate package-owned

## Configure this package

The Web settings forms submit package-owned changes through `/openpi-setup`; they do not introduce another settings writer. Role/model choices, concurrency, skill and plugin configuration requests remain visible in that episode, including required confirmation and its final apply/closure receipt. The Web submission message is not proof of persistence. Pi-owned model definitions and credentials have separate direct forms backed by Pi's `models.json` and native login API; secrets never enter the setup prompt.

Web shows the original setup command and its results, including failed or unapplied requests, rather than hiding the configuration episode. Appearance controls wait for the current run to settle before accepting another change. Chat-width and font-size reset buttons request the existing defaults through the same setup entry point. The model tree selects the editable Pi definition and retains unsaved drafts within the same Session; narrow screens use a labeled settings-section selector.

Each delivered setup request explicitly announces its new episode. Success and closure messages apply only to their completed episode; a later `/openpi-setup` request can activate the writer again without reusing the prior episode's authority.
The `compact` footer preset resolves to `plain` style with the default single-row layout; it is not a separate stored style. Applying it to the default footer does not change its appearance. Successful setup receipts distinguish saving the document from changing effective settings and list only fields that actually changed. Keeping defaults without invoking the writer does not create a file.

Explicit field assignments retain their meaning: `footerStyle="compact"` is invalid; the allowed styles are `plain`, `powerline`, and `powerline-mono`. Setup should explain the legal choices and wait for a valid choice instead of silently applying a preset or default. Requesting the `compact` preset is valid and resets both style and layout. Tool writes reject invalid footer styles and presets; stored invalid styles block writes rather than being repaired automatically.
Expand Down
9 changes: 9 additions & 0 deletions THIRD_PARTY_NOTICES.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@ revision `ebeb961` (Apache License 2.0). OpenPI uses its own Web host protocol
and headless Chromium/CDP implementation; it does not embed either project or
copy Maka's Electron-only `WebContentsView`.

The follow-up Git, file-preview and settings investigation also consulted
`agegr/pi-web` revision `1eb5e66a37c468aca7f0d338edb23de4fd84433e` (MIT),
`jmfederico/pi-web` revision `60a29acbfc710908e73b0df9857cb63b53b672d3` (MIT),
and `apache/maka` revision `0dc1142aa90000e45627017e846b6d57d1e165e0`
(Apache License 2.0). These are architectural references, not embedded packages.
The screencast sizing approach was informed by Chromium DevTools'
[`ScreencastView.ts`](https://github.com/ChromeDevTools/devtools-frontend/blob/main/front_end/panels/screencast/ScreencastView.ts)
(BSD-3-Clause). OpenPI retains its own bounded transport and Session authority.

## OAuth model providers

`extensions/ai-providers/` adapts protocol and OAuth details from
Expand Down
18 changes: 18 additions & 0 deletions docs/research/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,24 @@ Research records preserve sourced investigation and distinguish observations, in

## Validated investigations

- [`WEB_TURN_EVIDENCE_AND_ITEM_RECOVERY_2026-09-23.md`](WEB_TURN_EVIDENCE_AND_ITEM_RECOVERY_2026-09-23.md) — Codex-style paged Pi history/item recovery and per-user-turn Git evidence; local gates passed, CI pending ([#597](https://github.com/openpi-dev/openpi/issues/597), [PR #598](https://github.com/openpi-dev/openpi/pull/598)).

- [`WEB_GIT_REVIEW_IDENTITY_2026-09-23.md`](WEB_GIT_REVIEW_IDENTITY_2026-09-23.md) — 逐文件重命名两端、暂存/工作树比较对象身份及真实 Chromium 刷新验证([#597](https://github.com/openpi-dev/openpi/issues/597)、[PR #598](https://github.com/openpi-dev/openpi/pull/598))。

- [`WEB_READING_AND_LIFECYCLE_2026-09-22.md`](WEB_READING_AND_LIFECYCLE_2026-09-22.md) — 长会话历史、正文阅读、后台执行投影、待处理消息及输入控制文件身份;含真实 SDK 与 Chromium 验证([#597](https://github.com/openpi-dev/openpi/issues/597)、[PR #598](https://github.com/openpi-dev/openpi/pull/598))。

- [`WEB_INTERACTION_ROUND5_2026-09-22.md`](WEB_INTERACTION_ROUND5_2026-09-22.md) — 侧栏后台工作、图片粘贴与预览、设置布局、原生命令和完整回合耗时;含真实连续 setup 的正反证据与边界([#597](https://github.com/openpi-dev/openpi/issues/597)、[PR #598](https://github.com/openpi-dev/openpi/pull/598))。

- [`WEB_INTERACTION_ROUND4_2026-09-21.md`](WEB_INTERACTION_ROUND4_2026-09-21.md) — 表单回执、冲突重载、迟到凭据反馈、设置键盘导航与浏览器拖拽的第四轮验证([#597](https://github.com/openpi-dev/openpi/issues/597)、[PR #598](https://github.com/openpi-dev/openpi/pull/598))。

- [`WEB_INTERACTION_ROUND3_2026-09-21.md`](WEB_INTERACTION_ROUND3_2026-09-21.md) — 模型表单草稿、重复 diff 读取、本地浏览器地址、编辑组合键与指针请求积压的第三轮复现及修复([#597](https://github.com/openpi-dev/openpi/issues/597)、[PR #598](https://github.com/openpi-dev/openpi/pull/598))。

- [`WEB_NATIVE_INTERACTIONS_2026-09-20.md`](WEB_NATIVE_INTERACTIONS_2026-09-20.md) — Git 原生比较范围、CDP 浏览器、外部文件预览和 Pi 原生可编辑设置的参考调查与修复验收([#597](https://github.com/openpi-dev/openpi/issues/597)、[PR #598](https://github.com/openpi-dev/openpi/pull/598))。

- [`WEB_PR561_ASYNC_ITERATION_2026-09-20.md`](WEB_PR561_ASYNC_ITERATION_2026-09-20.md) — 第二轮 PR #561 测试:会话级变更投影、diff 焦点、终端队列及创建取消、文件引用清理;含合并后整合范围([#597](https://github.com/openpi-dev/openpi/issues/597)、[PR #561](https://github.com/openpi-dev/openpi/pull/561))。

- [`WEB_PR561_USAGE_ITERATION_2026-09-20.md`](WEB_PR561_USAGE_ITERATION_2026-09-20.md) — PR #561 使用测试:图片导入的发送与会话边界、浏览器粘贴与 Shift、键盘分栏([#597](https://github.com/openpi-dev/openpi/issues/597)、[PR #561](https://github.com/openpi-dev/openpi/pull/561))。

- [`WEB_MODULE_IMPLEMENTATION_2026-09-19.md`](WEB_MODULE_IMPLEMENTATION_2026-09-19.md) — Web 工作区十二模块的实现边界、现有/第三方组件复用判断、测试与非 Benchmark 的性能限制([#559](https://github.com/openpi-dev/openpi/issues/559)、[#560](https://github.com/openpi-dev/openpi/issues/560)、[PR #561](https://github.com/openpi-dev/openpi/pull/561))。

- [`WEB_SUBAGENT_INSPECTION_2026-09-18.md`](WEB_SUBAGENT_INSPECTION_2026-09-18.md) — 子代理任务总览、真实状态和只读子对话;含 Pi Web / Maka 组件参考及验证边界([#560](https://github.com/openpi-dev/openpi/issues/560))。
Expand Down
33 changes: 33 additions & 0 deletions docs/research/WEB_GIT_REVIEW_IDENTITY_2026-09-23.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Git review:重命名详情与比较身份

- Status: validated
- Created: 2026-09-23
- Verified: 2026-09-23
- Source boundary: OpenPI `0bc3470` + 本记录所在 PR #598 的 Git review 修复
- Issue: [#597](https://github.com/openpi-dev/openpi/issues/597)
- PR: [#598](https://github.com/openpi-dev/openpi/pull/598)
- Supersedes: none;补充[原生交互调查](WEB_NATIVE_INTERACTIONS_2026-09-20.md)

## 复现与根因

评审指出的两项问题在 `0bc3470` 仍可复现。真实临时仓库执行 `git mv` 后,暂存摘要正确显示 renamed,旧详情查询却在识别重命名前把 pathspec 限定为新路径,导致旧路径被排除,退化成新增文件。新回归包括纯重命名、重命名后编辑、分支比较,以及含方括号的字面文件名。

另用 `git hash-object` 与 `git update-index --cacheinfo` 只替换 index blob,保留工作文件的内容、size、mtime、ctime 不变;新旧暂存文本均为 +1/-1。旧摘要 revision 相同,但详情已经改变。未暂存视图也存在此问题,因为 index 是它的左端。只移动 HEAD、保持 index/工作文件不变,同样可能出现统计相同而比较内容不同。

## 修复

使用 [Git 官方 raw diff 格式](https://git-scm.com/docs/git-diff#_raw_output_format)中的完整前后对象 ID、文件模式、状态与路径生成比较身份,不读取 index 的 mtime,也不写入临时 tree 到用户仓库。工作树参与比较时继续保留有界文件元数据;纯暂存视图由 Git 比较身份决定,不受无关工作文件时间戳影响。

逐文件详情先在完整 raw 元数据中找出重命名两端,再用字面 pathspec 查询。详情的 raw 元数据和 patch 来自同一次 Git 调用,随后只返回请求的文件。摘要继续只读取元数据和 numstat,不加载整个工作区的 patch。保留已有超时、字节/文件数限额,以及禁用 external diff/textconv 的边界。

## 验证与限制

六项真实 Git 回归在旧实现上失败,修复后 Git review 的 15 项测试通过。分别移除旧路径和对象身份保护,两组回归重新失败;恢复后通过。没有引入第二份 Git 状态存储或新的配置选项。

真实 Chromium + WebHost + Git 用例确认:面板显示 `rename from` / `rename to`;外部只改变暂存 blob 后,经现有窗口 focus 刷新路径,仍打开的 diff 从 staged-a 更新为 staged-b,草稿及输入焦点保留。该用例不调用模型。

评审提到的滚轮失败属于较早提交 `4480b8d`。后续 `13465ad` 让测试夹具等待 React 被动效果,保留滚动合并与调用次数断言;`0bc3470` 的 Node 24 与全部 CI 已通过。本轮仍重跑完整门禁,以新提交的检查为准,不用历史绿色代替当前验收。

Git 命令之间不是仓库事务快照;并发编辑时仍依赖下一次刷新收敛。本轮不声称对 PR 全部文件完成手工浏览器验收,也不把局部响应时间当作性能 Benchmark。原始红绿、消融、浏览器截图和最终验证日志保存在私有 `openpi-pr561-usage-20260920/git-review-20260923`,不包含用户会话或凭据。

`81d4c67` 的 Node 22/24/26 与 Windows CI 通过;Web 任务在运行用例前的冷启动门禁失败。诊断记录首次给出无效 D-Bus 地址错误,端口文件仍未出现,后两次启动成功。CI 因而使用 [`dbus-run-session`](https://dbus.freedesktop.org/doc/dbus-run-session.1.html) 为冷启动和浏览器测试提供独立会话总线,随测试进程结束清理。此调整消除已知环境错误,不增加生产启动预算、不禁用 sandbox,也不证明此前所有启动超时都来自同一个原因;最终结果以新提交的 CI 为准。
Loading
Loading