Consolidate the browser task runtime around the callback path, add safer artifact opening for Zhihu exports, and cover the new service/browser flows with focused tests and supporting docs. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
482 lines
17 KiB
Markdown
482 lines
17 KiB
Markdown
# WS Browser Bridge Path Implementation Plan
|
|
|
|
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
|
|
|
**Goal:** Replace the raw-ws-direct browser execution assumption with a bridge-backed browser integration path that matches the validated FunctionsUI / BrowserAction / CommandRouter model while preserving existing pipe behavior.
|
|
|
|
**Architecture:** Keep the current Rust-side browser orchestration flow centered on `Arc<dyn BrowserBackend>`, but stop treating `WsBrowserBackend` as the real production browser surface. Model the validated bridge as two explicit layers: Layer 1 session/lifecycle calls (`sgclawConnect`, `sgclawStart`, `sgclawStop`, `sgclawSubmitTask`) and Layer 2 browser-action execution (`window.sgFunctionsUI(...)`, `window.BrowserAction(...)`, `CommandRouter`). The new backend targets Layer 2 only through a narrow repo-local `BridgeActionTransport` seam, while lifecycle/session concerns stay separate from per-action browser execution.
|
|
|
|
**Tech Stack:** Rust 2021, existing `BrowserBackend` abstraction, compat/runtime/orchestration stack, current service/task runner integration, existing bridge-oriented design docs, existing Rust unit/integration test suite.
|
|
|
|
---
|
|
|
|
## Scope Guardrails
|
|
|
|
- Do **not** continue extending raw external sgBrowser websocket business-frame handling as the mainline path.
|
|
- Do **not** modify `src/lib.rs`, pipe handshake behavior, or the working `BrowserPipeTool` path.
|
|
- Do **not** invent a parallel browser-command contract unrelated to the documented bridge surface.
|
|
- Do **not** rewrite the whole compat/runtime stack when a narrow adapter will do.
|
|
- Do **not** assume access to the full SuperRPA browser-host codebase from this repository; encode the validated contract at the nearest seam available here.
|
|
|
|
---
|
|
|
|
## File Structure
|
|
|
|
### Existing files to modify
|
|
|
|
- Modify: `src/browser/mod.rs`
|
|
- export the new bridge contract/transport/backend modules explicitly
|
|
- Modify: `src/browser/backend.rs`
|
|
- only if a tiny shared helper or trait documentation update is needed for the new bridge-backed backend
|
|
- Modify: `src/compat/browser_tool_adapter.rs`
|
|
- ensure existing browser action mapping remains reusable with the new backend implementation
|
|
- Modify: `src/compat/runtime.rs`
|
|
- wire the bridge-backed browser backend into the ws service/browser execution path without changing the pipe path
|
|
- Modify: `src/compat/orchestration.rs`
|
|
- only where browser backend wiring requires the bridge-backed path to flow through orchestration
|
|
- Modify: `src/compat/workflow_executor.rs`
|
|
- preserve direct-route/fallback use of `BrowserBackend` when the backend is bridge-backed instead of websocket-backed
|
|
- Modify: `src/service/server.rs`
|
|
- replace the current real-browser execution assumption with bridge-backend construction plus a repo-local bridge transport provider seam for the relevant service path
|
|
- Modify: `tests/compat_browser_tool_test.rs`
|
|
- extend browser tool mapping coverage if needed for bridge-backed execution
|
|
- Modify: `tests/service_task_flow_test.rs`
|
|
- replace raw-ws-direct expectations with bridge-path expectations where appropriate
|
|
- Modify: `tests/service_ws_session_test.rs`
|
|
- update service-side tests if they currently assume the real browser path is raw websocket driven
|
|
|
|
### New files to create
|
|
|
|
- Create: `src/browser/bridge_contract.rs`
|
|
- narrow, explicit contract types that keep lifecycle/session bridge calls separate from browser-action execution requests/replies
|
|
- Create: `src/browser/bridge_transport.rs`
|
|
- repo-local `BridgeActionTransport` seam used by the backend and injected by service/runtime wiring
|
|
- Create: `src/browser/bridge_backend.rs`
|
|
- new `BrowserBackend` implementation that maps browser actions onto the Layer-2 bridge action contract through `BridgeActionTransport`
|
|
- Create: `tests/browser_bridge_backend_test.rs`
|
|
- deterministic unit tests for action-to-bridge mapping and reply/error normalization using a fake bridge transport
|
|
- Create: `tests/browser_bridge_contract_test.rs`
|
|
- narrow tests proving the two bridge layers stay explicit and browser-action requests remain semantic rather than raw-websocket-shaped
|
|
|
|
### Evidence files to consult during implementation
|
|
|
|
- Read: `docs/_tmp_sgbrowser_ws_probe_transcript.md`
|
|
- Read: `frontend/archive/sgClaw验证-已归档/testRunner.js`
|
|
- Read: `docs/superpowers/specs/2026-03-25-superrpa-sgclaw-browser-control-design.md`
|
|
- Read: `docs/archive/项目管理与排期/协作时间表.md`
|
|
- Read: `docs/plans/2026-03-27-sgclaw-floating-chat-frontend-design.md`
|
|
|
|
---
|
|
|
|
## Task 1: Lock the bridge contract in deterministic tests before adding the backend
|
|
|
|
**Files:**
|
|
- Create: `src/browser/bridge_contract.rs`
|
|
- Create: `tests/browser_bridge_contract_test.rs`
|
|
- Reuse as design evidence:
|
|
- `frontend/archive/sgClaw验证-已归档/testRunner.js`
|
|
- `docs/archive/项目管理与排期/协作时间表.md`
|
|
- `docs/plans/2026-03-27-sgclaw-floating-chat-frontend-design.md`
|
|
|
|
- [ ] **Step 1: Write the first failing contract test for named bridge calls**
|
|
|
|
Create `tests/browser_bridge_contract_test.rs` with one focused test that encodes the bridge naming expectations already evidenced in the repo.
|
|
|
|
Start with a test shape like:
|
|
|
|
```rust
|
|
#[test]
|
|
fn bridge_contract_names_match_documented_bridge_surface() {
|
|
// assert the contract contains the exact bridge action names
|
|
}
|
|
```
|
|
|
|
Required expectations:
|
|
- `sgclawConnect`
|
|
- `sgclawStart`
|
|
- `sgclawStop`
|
|
- `sgclawSubmitTask`
|
|
- these names live in an explicit lifecycle/session contract type, not in the browser-action request type
|
|
|
|
Do **not** invent additional action names in this first test.
|
|
|
|
- [ ] **Step 2: Run the single contract test and verify it fails**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
cargo test --test browser_bridge_contract_test bridge_contract_names_match_documented_bridge_surface -- --nocapture
|
|
```
|
|
|
|
Expected: FAIL because `src/browser/bridge_contract.rs` does not exist yet.
|
|
|
|
- [ ] **Step 3: Add the second failing contract test for browser-action request shaping**
|
|
|
|
In the same file, add one focused test proving the bridge contract can represent a browser action request without leaking raw websocket business-frame semantics.
|
|
|
|
Test shape:
|
|
|
|
```rust
|
|
#[test]
|
|
fn bridge_contract_represents_browser_action_requests_without_ws_business_frames() {
|
|
// create a click/navigate/getText style action request and assert shape
|
|
}
|
|
```
|
|
|
|
Required assertions:
|
|
- request shape identifies the intended browser action semantically
|
|
- request shape is distinct from the lifecycle/session bridge call type
|
|
- request shape does **not** embed `sgBrowerserOpenPage`, `callBackJsToCpp`, or other raw websocket business-frame names
|
|
|
|
- [ ] **Step 4: Run the second contract test and verify it fails**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
cargo test --test browser_bridge_contract_test bridge_contract_represents_browser_action_requests_without_ws_business_frames -- --nocapture
|
|
```
|
|
|
|
Expected: FAIL because the bridge contract does not exist yet.
|
|
|
|
- [ ] **Step 5: Implement the minimal bridge contract module**
|
|
|
|
Create `src/browser/bridge_contract.rs` with only the types needed by the tests.
|
|
|
|
Recommended shape:
|
|
|
|
```rust
|
|
pub enum BridgeLifecycleCall {
|
|
Connect,
|
|
Start,
|
|
Stop,
|
|
SubmitTask,
|
|
}
|
|
|
|
impl BridgeLifecycleCall {
|
|
pub fn bridge_name(&self) -> &'static str {
|
|
match self {
|
|
Self::Connect => "sgclawConnect",
|
|
Self::Start => "sgclawStart",
|
|
Self::Stop => "sgclawStop",
|
|
Self::SubmitTask => "sgclawSubmitTask",
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct BridgeBrowserActionRequest {
|
|
pub action: String,
|
|
pub params: serde_json::Value,
|
|
pub expected_domain: String,
|
|
}
|
|
```
|
|
|
|
Rules:
|
|
- model the documented bridge/lifecycle naming explicitly
|
|
- keep the browser action request semantic, not websocket-frame-shaped
|
|
- keep the module small and repository-local
|
|
|
|
- [ ] **Step 6: Re-run the contract tests**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
cargo test --test browser_bridge_contract_test -- --nocapture
|
|
```
|
|
|
|
Expected: PASS.
|
|
|
|
- [ ] **Step 7: Commit**
|
|
|
|
```bash
|
|
git add src/browser/bridge_contract.rs tests/browser_bridge_contract_test.rs
|
|
git commit -m "test: define sgClaw bridge contract surface"
|
|
```
|
|
|
|
---
|
|
|
|
## Task 2: Add the repo-local transport seam and bridge-backed `BrowserBackend`
|
|
|
|
**Files:**
|
|
- Create: `src/browser/bridge_transport.rs`
|
|
- Create: `src/browser/bridge_backend.rs`
|
|
- Create: `tests/browser_bridge_backend_test.rs`
|
|
- Reuse: `src/browser/backend.rs`
|
|
- Reuse: `src/browser/bridge_contract.rs`
|
|
- Reuse: `src/compat/browser_tool_adapter.rs`
|
|
|
|
- [ ] **Step 1: Write the first failing backend test for action mapping**
|
|
|
|
Create `tests/browser_bridge_backend_test.rs` with one focused test proving a `BrowserBackend` action is translated into the bridge contract request shape.
|
|
|
|
Start with a narrow action such as `Action::Navigate`.
|
|
|
|
Required assertions:
|
|
- `Action::Navigate` becomes one semantic bridge browser-action request
|
|
- the request preserves action parameters and expected domain
|
|
- the test does **not** assert any raw websocket payload strings
|
|
|
|
- [ ] **Step 2: Run the first backend test and verify it fails**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
cargo test --test browser_bridge_backend_test bridge_backend_maps_navigate_to_bridge_action_request -- --nocapture
|
|
```
|
|
|
|
Expected: FAIL because `src/browser/bridge_backend.rs` does not exist yet.
|
|
|
|
- [ ] **Step 3: Add the second failing backend test for reply normalization**
|
|
|
|
Add one focused test proving the backend can normalize a successful bridge reply into the existing `CommandOutput` shape expected by `BrowserBackend` callers.
|
|
|
|
- [ ] **Step 4: Run the second backend test and verify it fails**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
cargo test --test browser_bridge_backend_test bridge_backend_normalizes_successful_bridge_reply -- --nocapture
|
|
```
|
|
|
|
Expected: FAIL because the backend does not exist yet.
|
|
|
|
- [ ] **Step 5: Add the third failing backend test for bridge-side errors**
|
|
|
|
Add one focused test proving a bridge-side error normalizes into the correct outward `PipeError` semantics for backend callers.
|
|
|
|
- [ ] **Step 6: Run the error-path test and verify it fails**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
cargo test --test browser_bridge_backend_test bridge_backend_maps_bridge_failure_to_pipe_error -- --nocapture
|
|
```
|
|
|
|
Expected: FAIL because the backend does not exist yet.
|
|
|
|
- [ ] **Step 7: Implement the minimal transport seam and bridge backend**
|
|
|
|
Create `src/browser/bridge_transport.rs` and `src/browser/bridge_backend.rs`.
|
|
|
|
The transport seam must:
|
|
- define the repo-local `BridgeActionTransport` contract used for Layer-2 browser-action execution only
|
|
- accept semantic `BridgeBrowserActionRequest` values and return semantic success/error replies
|
|
- remain small, explicit, and easy to fake in tests
|
|
|
|
The backend must:
|
|
- implement the existing `BrowserBackend` trait
|
|
- translate supported actions into `BridgeBrowserActionRequest`
|
|
- depend on `BridgeActionTransport` instead of raw websocket payload building
|
|
- normalize success/error replies into existing backend-facing result types
|
|
|
|
Rules:
|
|
- do not embed raw websocket business-frame names
|
|
- do not change `BrowserBackend` semantics for existing callers
|
|
- do not pull lifecycle/session bridge calls into this backend layer
|
|
|
|
- [ ] **Step 8: Re-run the bridge backend tests**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
cargo test --test browser_bridge_backend_test -- --nocapture
|
|
```
|
|
|
|
Expected: PASS.
|
|
|
|
- [ ] **Step 9: Re-run browser tool adapter coverage**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
cargo test --test compat_browser_tool_test -- --nocapture
|
|
```
|
|
|
|
Expected: PASS, proving the existing browser action mapping remains reusable with the new backend.
|
|
|
|
- [ ] **Step 10: Commit**
|
|
|
|
```bash
|
|
git add src/browser/bridge_transport.rs src/browser/bridge_backend.rs tests/browser_bridge_backend_test.rs src/compat/browser_tool_adapter.rs src/browser/mod.rs
|
|
git commit -m "feat: add bridge-backed browser backend"
|
|
```
|
|
|
|
---
|
|
|
|
## Task 3: Wire the bridge-backed backend into the real-browser service path
|
|
|
|
**Files:**
|
|
- Modify: `src/service/server.rs`
|
|
- Modify: `src/compat/runtime.rs`
|
|
- Modify: `src/compat/orchestration.rs`
|
|
- Modify: `src/compat/workflow_executor.rs`
|
|
- Modify: `tests/service_task_flow_test.rs`
|
|
- Modify: `tests/service_ws_session_test.rs`
|
|
- Reuse: `src/browser/bridge_backend.rs`
|
|
- Reuse: `src/browser/bridge_contract.rs`
|
|
- Reuse: `src/browser/bridge_transport.rs`
|
|
|
|
- [ ] **Step 1: Write the first failing service-path test for bridge backend construction**
|
|
|
|
Add or update one focused service test proving the real-browser execution path constructs and uses the bridge-backed backend instead of the raw websocket backend assumption.
|
|
|
|
The test should observe backend selection at the nearest possible seam.
|
|
|
|
- [ ] **Step 2: Run the focused service test and verify it fails**
|
|
|
|
Run the narrowest affected service test command.
|
|
|
|
Expected: FAIL because the service path is not wired to the bridge backend yet.
|
|
|
|
- [ ] **Step 3: Add the minimal service/runtime wiring**
|
|
|
|
Change the relevant service/browser execution path so it constructs the new bridge-backed backend, injects the repo-local bridge transport provider at the nearest seam, and passes the backend through the existing runtime/orchestration flow.
|
|
|
|
Rules:
|
|
- keep the pipe path unchanged
|
|
- keep changes localized
|
|
- keep lifecycle/session bridge handling separate from per-action browser execution
|
|
- preserve existing runtime log and task flow behavior where possible
|
|
|
|
- [ ] **Step 4: Add one direct-route/fallback regression**
|
|
|
|
Add one focused regression proving a bridge-backed backend still works through the direct-route or fallback path exercised by `src/compat/workflow_executor.rs`.
|
|
|
|
- [ ] **Step 5: Run the bridge-focused service tests**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
cargo test --test service_ws_session_test --test service_task_flow_test -- --nocapture
|
|
```
|
|
|
|
Expected: PASS.
|
|
|
|
- [ ] **Step 6: Re-run workflow/runtime regressions**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
cargo test compat::workflow_executor::tests -- --nocapture
|
|
cargo test --test compat_browser_tool_test --test browser_script_skill_tool_test --test task_runner_test -- --nocapture
|
|
```
|
|
|
|
Expected: PASS.
|
|
|
|
- [ ] **Step 7: Commit**
|
|
|
|
```bash
|
|
git add src/service/server.rs src/compat/runtime.rs src/compat/orchestration.rs src/compat/workflow_executor.rs tests/service_ws_session_test.rs tests/service_task_flow_test.rs
|
|
git commit -m "refactor: route real browser path through bridge backend"
|
|
```
|
|
|
|
---
|
|
|
|
## Task 4: Verify bridge-path behavior without pipe regression
|
|
|
|
**Files:**
|
|
- Reuse only unless a failing test proves a minimal fix is still needed
|
|
|
|
- [ ] **Step 1: Run bridge/backend unit coverage**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
cargo test --test browser_bridge_contract_test --test browser_bridge_backend_test -- --nocapture
|
|
```
|
|
|
|
Expected: PASS.
|
|
|
|
- [ ] **Step 2: Run service/runtime bridge-path regressions**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
cargo test --test service_ws_session_test --test service_task_flow_test -- --nocapture
|
|
```
|
|
|
|
Expected: PASS.
|
|
|
|
- [ ] **Step 3: Run required pipe regressions**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
cargo test --test pipe_handshake_test --test browser_tool_test --test compat_browser_tool_test --test browser_script_skill_tool_test --test runtime_task_flow_test -- --nocapture
|
|
```
|
|
|
|
Expected: PASS.
|
|
|
|
- [ ] **Step 4: Build the affected binaries**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
cargo build --bin sgclaw --bin sg_claw --bin sg_claw_client
|
|
```
|
|
|
|
Expected: PASS.
|
|
|
|
- [ ] **Step 5: Stop if any regression points back to raw websocket assumptions**
|
|
|
|
If any test still encodes raw external websocket business-frame assumptions as the real-browser path, update that test to the bridge-backed design rather than patching production code to satisfy the old assumption.
|
|
|
|
- [ ] **Step 6: Commit**
|
|
|
|
```bash
|
|
git add tests/browser_bridge_contract_test.rs tests/browser_bridge_backend_test.rs tests/service_ws_session_test.rs tests/service_task_flow_test.rs
|
|
git commit -m "test: verify bridge path and preserve pipe behavior"
|
|
```
|
|
|
|
---
|
|
|
|
## Verification Checklist
|
|
|
|
### Bridge contract tests
|
|
|
|
```bash
|
|
cargo test --test browser_bridge_contract_test -- --nocapture
|
|
```
|
|
|
|
Expected: documented bridge names and semantic browser-action request shaping are locked.
|
|
|
|
### Bridge backend tests
|
|
|
|
```bash
|
|
cargo test --test browser_bridge_backend_test -- --nocapture
|
|
```
|
|
|
|
Expected: backend action mapping and reply/error normalization are green.
|
|
|
|
### Service/runtime integration tests
|
|
|
|
```bash
|
|
cargo test --test service_ws_session_test --test service_task_flow_test -- --nocapture
|
|
cargo test compat::workflow_executor::tests -- --nocapture
|
|
```
|
|
|
|
Expected: real-browser path uses the bridge-backed backend and direct-route/fallback behavior remains intact.
|
|
|
|
### Pipe regressions
|
|
|
|
```bash
|
|
cargo test --test pipe_handshake_test --test browser_tool_test --test compat_browser_tool_test --test browser_script_skill_tool_test --test runtime_task_flow_test -- --nocapture
|
|
```
|
|
|
|
Expected: pipe path remains unchanged.
|
|
|
|
### Binary build verification
|
|
|
|
```bash
|
|
cargo build --bin sgclaw --bin sg_claw --bin sg_claw_client
|
|
```
|
|
|
|
Expected: affected binaries compile.
|
|
|
|
---
|
|
|
|
## Notes for Implementation
|
|
|
|
- The websocket probe work stays in the repository as diagnostic tooling; do not repurpose it into the bridge adapter.
|
|
- `docs/_tmp_sgbrowser_ws_probe_transcript.md` is evidence that rejected the raw-ws-direct assumption, not a contract to keep satisfying.
|
|
- Favor one narrow bridge-backed backend over broad runtime rewrites.
|
|
- If the nearest repo-local seam is still slightly abstract because the external SuperRPA host code is outside this repository, make that abstraction explicit and test it rather than guessing hidden behavior. |