Files
claw/docs/superpowers/plans/2026-04-03-ws-browser-bridge-path-plan.md
木炎 bdf8e12246 feat: align browser callback runtime and export flows
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>
2026-04-06 21:44:53 +08:00

17 KiB

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:

#[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:

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:

#[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:

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:

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:

cargo test --test browser_bridge_contract_test -- --nocapture

Expected: PASS.

  • Step 7: Commit
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:

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:

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:

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:

cargo test --test browser_bridge_backend_test -- --nocapture

Expected: PASS.

  • Step 9: Re-run browser tool adapter coverage

Run:

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
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:

cargo test --test service_ws_session_test --test service_task_flow_test -- --nocapture

Expected: PASS.

  • Step 6: Re-run workflow/runtime regressions

Run:

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
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:

cargo test --test browser_bridge_contract_test --test browser_bridge_backend_test -- --nocapture

Expected: PASS.

  • Step 2: Run service/runtime bridge-path regressions

Run:

cargo test --test service_ws_session_test --test service_task_flow_test -- --nocapture

Expected: PASS.

  • Step 3: Run required pipe regressions

Run:

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:

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
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

cargo test --test browser_bridge_contract_test -- --nocapture

Expected: documented bridge names and semantic browser-action request shaping are locked.

Bridge backend tests

cargo test --test browser_bridge_backend_test -- --nocapture

Expected: backend action mapping and reply/error normalization are green.

Service/runtime integration tests

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

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

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.