Expose one typed facade bridge for native computer-use adapters - #2904
Expose one typed facade bridge for native computer-use adapters#2904miguelg719 wants to merge 12 commits into
Conversation
|
There was a problem hiding this comment.
All reported issues were addressed across 2 files
Architecture diagram
sequenceDiagram
participant Adapter as Native CUA Adapter
participant Bridge as cuaToolAdapter Bridge
participant Channel as Tool Caller (MCP Channel)
participant Facade as Stagehand Facade (Canonical)
participant Browser as Runner-Owned Browser
Note over Adapter,Browser: Shared Typed Facade Bridge for Native Computer-Use Adapters
Adapter->>Bridge: bridgeCuaFacadeTools(callTool, timeoutMs)
Bridge->>Channel: run(name, args, { timeoutMs })
alt run() method
Bridge->>Channel: run("run", { code })
Channel-->>Bridge: Tool result (text or error)
Bridge->>Bridge: Decode result text
Bridge-->>Adapter: Parsed result (JSON or string)
else runActions() method
Bridge->>Channel: run("run", { actions })
Channel-->>Bridge: Tool result (text)
Bridge->>Bridge: Validate completed/url shape
alt Valid result
Bridge-->>Adapter: { completed, url }
else Invalid result
Bridge-->>Adapter: Throw "invalid result"
end
else snapshot() method
Bridge->>Channel: run("snapshot", { includeIframes })
Channel-->>Bridge: Tool result
Bridge-->>Adapter: Snapshot text
else screenshot() method
Bridge->>Channel: run("screenshot", { ...options })
Channel-->>Bridge: Tool result (image blocks)
alt Image block found (PNG/JPEG)
Bridge-->>Adapter: { data, mimeType }
else No image
Bridge-->>Adapter: Throw "no image"
end
end
Note over Adapter,Bridge: Error propagation
alt result.isError
Bridge->>Bridge: Extract error text
Bridge-->>Adapter: Throw Error
end
Note over Adapter,Bridge: Evidence Capture
Adapter->>Bridge: captureCuaEvidence(callTool)
Bridge->>Bridge: Create bridge with 15s timeout
Bridge->>Channel: screenshot({ type: "jpeg", quality: 60 })
alt Screenshot success
Bridge->>Bridge: Buffer.from(base64 data)
Bridge-->>Adapter: evidence.screenshot
else Browser session lost
Bridge-->>Adapter: Re-throw terminal error
end
Bridge->>Channel: run(return page.url())
alt URL valid scheme
Bridge-->>Adapter: evidence.url
else Browser session lost
Bridge-->>Adapter: Re-throw terminal error
end
Note over Adapter,Bridge: Bounded Idempotent Cleanup
Adapter->>Bridge: cuaCleanup(cleanupFn, timeoutMs)
Bridge->>Bridge: Create pending promise (shared)
Bridge->>Bridge: Execute cleanup once
alt Cleanup settles within timeout
Bridge-->>Adapter: Resolve
else Cleanup never settles
Note over Bridge: Timer forces resolve after timeoutMs
Bridge-->>Adapter: Resolve (bounded)
end
Note over Adapter,Browser: Loopback MCP Fixture Path
Bridge->>Channel: callTool through MCP transport
Channel->>Facade: MCP tools/call (run/snapshot/screenshot)
Facade->>Browser: Execute against active page/context
Browser-->>Facade: Response data
Facade-->>Channel: Encoded result
Channel-->>Bridge: Decoded result
Bridge-->>Adapter: Typed result
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
…15-shared-cua-bridge
…15-shared-cua-bridge
…15-shared-cua-bridge
70b194d to
55f180a
Compare
2b3676a to
0497a2d
Compare
There was a problem hiding this comment.
All reported issues were addressed across 4 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
…15-shared-cua-bridge
Provides one typed bridge from native computer-use adapters to the canonical facade on the runner-owned browser. The bridge centralizes MCP results, screenshots, evidence capture, and failure decoding; provider protocols remain in their own adapters.
An internal callback envelope preserves strings such as
"42"and"null"as strings while also preserving JSON values andundefined. Malformed action results and incomplete action batches fail explicitly. Visible facade pages also expose their read-only StagehandpageId, so native tab tools can use the shared visible context without reaching into the hidden keeper tab. Tool and transport failures use fixed typed diagnostics. Runner RPC deadlines now raise a typedStagehandFacadeTimeoutErrorcarryingtimeoutMs; the CUA adapter preserves that duration while keeping arbitrary transport-error text generic. Confirmed session loss still takes precedence. Only the runner-owned browser-loss getter can produce terminal session loss, so page content and model-written error strings cannot stop a run by impersonating that signal.Validation: 23 bridge and transport tests pass, including the compiled facade/MCP fixture, an actual expired RPC, preserved timeout duration, generic handling of spoofed timeout text, and confirmed session loss. Eval typecheck, build prerequisites, and formatting pass.
Stack position: 15/17. Base:
external-contributor-pr-2771(#2889, the reused Cursor SDK contribution). Review the diff against the immediate predecessor.Reviewer entry points:
packages/evals/framework/cuaToolAdapter.tspackages/evals/tests/framework/cuaToolAdapter.test.ts