From ee488d2c8a004b821e245ee27fc5511ba2c507ec Mon Sep 17 00:00:00 2001 From: Neil Date: Wed, 11 Nov 2026 02:17:35 -0800 Subject: [PATCH] fix(br-1): cloud never falls back to the stream path; final non-http and retry copy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Orca Cloud counts as no screencast until a probe proves otherwise, so a sleeping or unreachable sandbox cannot surface 'Cannot reach…' stream notices (BR-2 closes with this). Non-http pages: 'Orca can't show the sandbox's browser here yet.' + 'This page can only be viewed in the sandbox.' A failed open says 'Couldn't open the page. Try again.' (polite live region). --- ...andbox-only-browser-page-state.fixture.tsx | 6 ++-- .../sandbox-only-browser-page-state.test.ts | 18 ++++++++++ .../sandbox-only-browser-page-state.tsx | 30 ++++++++++------ .../use-sandbox-only-browser-page.ts | 35 ++++++++++++++----- src/renderer/src/i18n/locales/en.json | 4 ++- 5 files changed, 70 insertions(+), 23 deletions(-) diff --git a/src/renderer/src/components/browser-pane/stream-remote/sandbox-only-browser-page-state.fixture.tsx b/src/renderer/src/components/browser-pane/stream-remote/sandbox-only-browser-page-state.fixture.tsx index 9d07af4e795..51295844cc5 100644 --- a/src/renderer/src/components/browser-pane/stream-remote/sandbox-only-browser-page-state.fixture.tsx +++ b/src/renderer/src/components/browser-pane/stream-remote/sandbox-only-browser-page-state.fixture.tsx @@ -1,7 +1,7 @@ import { defineFixture } from '../../../component-fixtures/component-fixture' import { SandboxOnlyBrowserPageState } from './sandbox-only-browser-page-state' -function Pane({ url, error = null }: { url: string; error?: string | null }): React.JSX.Element { +function Pane({ url, error = false }: { url: string; error?: boolean }): React.JSX.Element { return (
@@ -29,7 +29,5 @@ export const nonHttp = defineFixture({ }) export const openFailed = defineFixture({ width: 740, - render: () => ( - - ) + render: () => }) diff --git a/src/renderer/src/components/browser-pane/stream-remote/sandbox-only-browser-page-state.test.ts b/src/renderer/src/components/browser-pane/stream-remote/sandbox-only-browser-page-state.test.ts index 3310d7be149..4e3120bf22d 100644 --- a/src/renderer/src/components/browser-pane/stream-remote/sandbox-only-browser-page-state.test.ts +++ b/src/renderer/src/components/browser-pane/stream-remote/sandbox-only-browser-page-state.test.ts @@ -1,5 +1,6 @@ import { describe, expect, it } from 'vitest' import { canOpenSandboxPageOnThisComputer } from './sandbox-only-browser-page-state' +import { resolveScreencastSupport } from './use-sandbox-only-browser-page' describe('canOpenSandboxPageOnThisComputer', () => { it('offers http(s) pages, including the sandbox localhost', () => { @@ -15,3 +16,20 @@ describe('canOpenSandboxPageOnThisComputer', () => { expect(canOpenSandboxPageOnThisComputer('not a url')).toBe(false) }) }) + +describe('resolveScreencastSupport', () => { + it('treats a pending or failed probe as no screencast on Orca Cloud', () => { + expect(resolveScreencastSupport('pending', true)).toBe(false) + expect(resolveScreencastSupport('failed', true)).toBe(false) + expect(resolveScreencastSupport(false, true)).toBe(false) + // A future orcad that streams is honoured once proven. + expect(resolveScreencastSupport(true, true)).toBe(true) + }) + + it('keeps other hosts on the stream path until the probe says otherwise', () => { + expect(resolveScreencastSupport('pending', false)).toBe(null) + expect(resolveScreencastSupport('failed', false)).toBe(null) + expect(resolveScreencastSupport(true, false)).toBe(true) + expect(resolveScreencastSupport(false, false)).toBe(false) + }) +}) diff --git a/src/renderer/src/components/browser-pane/stream-remote/sandbox-only-browser-page-state.tsx b/src/renderer/src/components/browser-pane/stream-remote/sandbox-only-browser-page-state.tsx index 70f9b0a2f5c..c2b1c1a0669 100644 --- a/src/renderer/src/components/browser-pane/stream-remote/sandbox-only-browser-page-state.tsx +++ b/src/renderer/src/components/browser-pane/stream-remote/sandbox-only-browser-page-state.tsx @@ -24,11 +24,16 @@ export function SandboxOnlyBrowserPageState({ }: { url: string opening: boolean - error: string | null + /** The last open attempt failed; the button doubles as the retry. */ + error: boolean onOpenOnThisComputer: () => void }): React.JSX.Element { const t = useTranslate() const canOpen = canOpenSandboxPageOnThisComputer(url) + const cantShow = t( + 'auto.components.browser.pane.SandboxOnlyBrowserPage.cantShow', + "Orca can't show the sandbox's browser here yet." + ) return (
- {t( - 'auto.components.browser.pane.SandboxOnlyBrowserPage.body', - "Orca can't show the sandbox's browser here yet. Open the page on this computer to see it. Pages the agent signed in to will open signed out." - )} + {canOpen + ? t( + 'auto.components.browser.pane.SandboxOnlyBrowserPage.body', + "Orca can't show the sandbox's browser here yet. Open the page on this computer to see it. Pages the agent signed in to will open signed out." + ) + : cantShow}
{canOpen ? (
)} - {error ? ( -
- {error} -
- ) : null} +
+ {error && canOpen + ? t( + 'auto.components.browser.pane.SandboxOnlyBrowserPage.openFailed', + "Couldn't open the page. Try again." + ) + : null} +
) } diff --git a/src/renderer/src/components/browser-pane/stream-remote/use-sandbox-only-browser-page.ts b/src/renderer/src/components/browser-pane/stream-remote/use-sandbox-only-browser-page.ts index 6fe930789a2..20baeb9de6f 100644 --- a/src/renderer/src/components/browser-pane/stream-remote/use-sandbox-only-browser-page.ts +++ b/src/renderer/src/components/browser-pane/stream-remote/use-sandbox-only-browser-page.ts @@ -4,15 +4,30 @@ import { BROWSER_SCREENCAST_RUNTIME_CAPABILITY } from '../../../../../shared/bro import { runtimeEnvironmentSupportsCapability } from '@/runtime/rpc/compatibility/runtime-capability-proof' import { openWorkspaceBrowserTab } from '@/lib/browser/workspace/workspace-browser-tab-open' import { resolveBrowserSourceUnifiedTab } from '@/lib/browser/workspace/browser-workspace-source-resolution' +import { isOrcaCloudEnvironmentId } from '@/lib/orca-cloud/orca-cloud-environment-id' export type SandboxOnlyBrowserPage = { /** False when the runtime cannot stream (Orca Cloud's orcad); null while unknown, which keeps the stream path. */ screencastSupported: boolean | null opening: boolean - error: string | null + error: boolean openOnThisComputer: () => void } +/** + * Whether the stream path may run. Orca Cloud counts as no screencast until a probe proves it (a sleeping or + * unreachable sandbox must not fall back to "Cannot reach…" notices); other hosts stay unknown (null) until proven. + */ +export function resolveScreencastSupport( + probe: 'pending' | 'failed' | boolean, + isOrcaCloud: boolean +): boolean | null { + if (typeof probe === 'boolean') { + return probe + } + return isOrcaCloud ? false : null +} + /** * Orca Cloud's orcad hosts agent pages in a headless browser it cannot stream; offer a * desktop-hosted copy of the page instead. @@ -24,25 +39,29 @@ export function useSandboxOnlyBrowserPage(input: { worktreeId: string }): SandboxOnlyBrowserPage { const { pageId, url, runtimeEnvironmentId, worktreeId } = input - const [screencastSupported, setScreencastSupported] = useState(null) + const [probe, setProbe] = useState<'pending' | 'failed' | boolean>('pending') const [opening, setOpening] = useState(false) - const [error, setError] = useState(null) + const [error, setError] = useState(false) + const screencastSupported = resolveScreencastSupport( + probe, + isOrcaCloudEnvironmentId(runtimeEnvironmentId) + ) useEffect(() => { let cancelled = false + setProbe('pending') void runtimeEnvironmentSupportsCapability( runtimeEnvironmentId, BROWSER_SCREENCAST_RUNTIME_CAPABILITY ) .then((supported) => { if (!cancelled) { - setScreencastSupported(supported) + setProbe(supported) } }) .catch(() => { - // Unknown support keeps the stream path, which reports its own failures. if (!cancelled) { - setScreencastSupported(null) + setProbe('failed') } }) return () => { @@ -57,7 +76,7 @@ export function useSandboxOnlyBrowserPage(input: { worktreeId ) setOpening(true) - setError(null) + setError(false) // A new focused desktop-hosted tab beside this one; the sandbox tab stays so the agent's tab id remains valid. // Desktop-hosted cloud pages tunnel loopback through the sandbox, so localhost reaches the sandbox's server. void openWorkspaceBrowserTab({ @@ -70,7 +89,7 @@ export function useSandboxOnlyBrowserPage(input: { expectedRuntimeEnvironmentId: runtimeEnvironmentId, placementPreference: 'auto' }) - .catch((cause) => setError(cause instanceof Error ? cause.message : String(cause))) + .catch(() => setError(true)) .finally(() => setOpening(false)) }, [pageId, url, runtimeEnvironmentId, worktreeId]) diff --git a/src/renderer/src/i18n/locales/en.json b/src/renderer/src/i18n/locales/en.json index 0d8ae86c23a..098f4d2aee9 100644 --- a/src/renderer/src/i18n/locales/en.json +++ b/src/renderer/src/i18n/locales/en.json @@ -19011,7 +19011,9 @@ "title": "Your agent opened this page in the sandbox", "body": "Orca can't show the sandbox's browser here yet. Open the page on this computer to see it. Pages the agent signed in to will open signed out.", "open": "Open on this computer", - "sandboxOnly": "This page can only be viewed in the sandbox." + "sandboxOnly": "This page can only be viewed in the sandbox.", + "cantShow": "Orca can't show the sandbox's browser here yet.", + "openFailed": "Couldn't open the page. Try again." } }, "webauthn": {