refactor(web): migrate the Web workbench UI to React - #384
Conversation
Record the frozen PR openpi-dev#352 behavior baseline, Pi-native ownership boundaries, selected frontend stack, static delivery contract, and validation matrix for the local migration experiment.
Document default port fallback, strict explicit ports, fast startup diagnostics, and TUI error projection for the local React validation branch.
- replace the imperative browser UI with typed React and Zustand projections - add Vite HMR, production asset builds, and bounded port conflict handling - cover the Web store, packaged host, responsive browser flows, and artifact drift in CI
|
@tt-a1i Could you please review the technical direction and implementation of this React Web MVP? Thanks. |
|
来了
涂少坤
***@***.***
…---Original---
From: ***@***.***>
Date: Fri, Sep 4, 2026 17:53 PM
To: ***@***.***>;
Cc: ***@***.******@***.***>;
Subject: Re: [openpi-dev/openpi] refactor(web): migrate the Web workbench UI to React (PR #384)
6iKUN6 left a comment (openpi-dev/openpi#384)
@tt-a1i 麻烦帮忙 review 一下这个 React Web MVP 的技术方向和实现,谢谢。
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you were mentioned.Message ID: ***@***.***>
|
- disable npm peer resolution for Pi-provided host packages - guard the Git install contract and record the production smoke rationale
tt-a1i
left a comment
There was a problem hiding this comment.
The React direction is sound and keeps Pi as the runtime source of truth, but this draft is not ready to merge yet. I found two user-visible parity regressions, an unenforced development-startup bound, a supported-Node test failure, and a distribution-notice gap.
I reviewed exact head 13f3032decdcc600e7d46d848b2cc0097fd54d7e. Locally, bun run check and bun run test:web:e2e pass (3/3). On Node 26.3.0, the focused Web store suite fails 21/21 because the tests access an unavailable unqualified localStorage. The required Node 22 CI job is also currently red: the packed standalone CLI smoke attempts to fetch unavailable @earendil-works/pi-tui@0.85.0 and receives 404, so the recorded installed-package validation is not current.
Please also update the design record's source boundary to identify this PR and an exact implementation head when the evidence is frozen, rather than only a mutable local branch plus the base and PR #352.
| if (startupFailure) throw startupFailure; | ||
| try { | ||
| const response = await fetch(endpoint); | ||
| const response = await fetch(endpoint, { |
There was a problem hiding this comment.
[P1] Enforce the advertised readiness deadline on each probe. The outer 15-second loop does not bound this awaited fetch: a peer can accept the TCP connection and never return headers, leaving dev:web stuck here forever and preventing startup.waitForFailure() from being observed. Please abort each request at the remaining deadline (and when startup fails), and add a hanging-peer regression test.
| } | ||
| }, | ||
| setQuery(query) { | ||
| set({ query: query.trim() }); |
There was a problem hiding this comment.
[P2] Preserve the raw value of this controlled input. Trimming in the setter rewrites "foo " to "foo" immediately; typing the next character then produces "foobar" instead of "foo bar". Keep the raw query in state and trim only the value used for matching, with a test covering spaces in a search term.
| return ( | ||
| <div className="markdown"> | ||
| <ReactMarkdown | ||
| remarkPlugins={[remarkGfm]} |
There was a problem hiding this comment.
[P2] Preserve the frozen baseline's soft-line-break behavior. PR #352 configured Marked with breaks: true, while GFM alone renders "first line\nsecond line" without a <br>; this component sits under .message-content, so it does not inherit the user-message white-space: pre-wrap rule and the browser collapses the newline. Add remark-breaks (or an equivalent rendering rule) and a parity test.
|
|
||
| afterEach(() => { | ||
| sessionStorage.clear(); | ||
| localStorage.clear(); |
There was a problem hiding this comment.
[P2] Keep this suite compatible with the declared node >=22.19.0 range. Under Node 26.3.0, the native Web Storage global shadows jsdom and unqualified localStorage is undefined, so all 21 store tests fail in this cleanup. I reproduced the same failure at this head. Use window.localStorage (including the assertion below) or explicitly configure the test environment, then cover a supported newer Node in CI.
| "undici": "8.9.0" | ||
| }, | ||
| "devDependencies": { | ||
| "@astryxdesign/core": "0.5.2", |
There was a problem hiding this comment.
[P1] Add notices for the code now shipped in the committed production bundle. web/dist/app.js embeds React/ReactDOM, Zustand, Lucide, i18next, eventsource-parser, React Markdown/remark/rehype, Astryx, and related runtime code, but THIRD_PARTY_NOTICES.md still lists only the Sessions extension. The relevant MIT/ISC terms and retained copyright notices need to accompany distribution before this can leave draft.
|
Reviewed at exact head The React/Pi-native direction looks good, but the draft still needs fixes for the unbounded development readiness probe, controlled-search whitespace regression, Markdown soft-break parity, Node 26 Web-store test compatibility, and bundled frontend notices. The required Node 22 packed-CLI smoke is also currently failing with an unavailable |
Use an explicitly referenced timer for each readiness probe so Node 22 does not let the test process or launcher exit while the fetch is still pending. Clear the timer after every probe.
Advance the design evidence boundary to the readiness timer fix and record the focused Node 22 and Node 24 regression runs.
Replace the superseded load-sensitive test note with the successful Node 24 full-suite result observed after the readiness fix.
Ensure the CLI cannot advertise a ready Web Host before its SIGINT and SIGTERM cleanup handlers are installed.
Advance the implementation boundary and distinguish focused CLI evidence from unrelated full-suite timing failures.
|
@tt-a1i The review feedback has been addressed, the merge conflict is resolved, and CI is green. Could you please re-review when convenient? |
prompt_accepted and the HTTP receipt were resetting an active turn to preparing. Preserve running unless the command already settled, matching the openpi-dev#364 live-phase rule without copying legacy app.js.
Bring live main (openpi-dev#374, openpi-dev#356, openpi-dev#310, openpi-dev#293, openpi-dev#336) onto 91eb223 without rewriting author history. No theme work.
Problem
The Web workbench's imperative browser script mixes transcript rendering, Session navigation, streaming state, and interaction logic. This PR replaces it with typed React components and a browser store. Related to #76; the visual reference is #352 at
1b340f2, while compatibility follows current main0b282430798939a19412ff83fce277916f5d0cf1.The integration review found missing newer-main behavior in the original React branch: exact turn cancellation, canonical theme preference, reliable prompt admission/retry and queue receipts, quiet/stalled connection recovery, and running-state protection. These are restored before merge.
Value
Give the workbench component, state, and protocol boundaries that are easier to maintain and test, with Vite HMR for development and self-contained production assets. The React implementation carries forward #352's visual work; merging the legacy implementation separately is unnecessary.
Approach
Validation
Final integrated source HEAD:
71462796f60246e9e0cf0eb35e3545ba72f8ae99.bun run check: passed, including frontend build/typecheck, format and lint.bun run test: 1,442 Node tests passed, one platform skip; 81 Vitest tests passed.bun run test:web:e2eusing local Chrome: 4 passed, including desktop/mobile, reduced motion, dark running state, exact cancellation request, and axe checks.npm pack --dry-run --json: all four production assets included.pi listidentified only this checkout; offline RPC startup exposed the expected OpenPI status/widget without errors.Browser tests run the production WebHost. The running/cancellation fixture intercepts canonical snapshots and command receipts; it is not a live-provider or long-running Workflow acceptance claim. The user's installed OpenPI source was not changed.
Impact
The browser implementation and development/build tooling change. Backend protocol, model-visible tools/context, permissions, Session persistence and canonical configuration do not change. Theme continues to use Pi's existing preference. Production remains local and self-contained, with no Vite/CDN requirement at runtime.
The single JavaScript bundle is approximately 714 kB raw / 213 kB gzip and still triggers Vite's size warning. This is a maintainability migration, without a measured rendering-speedup claim. Historical Markdown parsing during streaming remains a separate performance opportunity.
Design and integration evidence.