diff --git a/src/components/CloudBackendPicker.tsx b/src/components/CloudBackendPicker.tsx
index 35e099aa9d..ba85220803 100644
--- a/src/components/CloudBackendPicker.tsx
+++ b/src/components/CloudBackendPicker.tsx
@@ -19,7 +19,7 @@ export function CloudBackendPicker({
Cloud backend
{value === "vps"
- ? "Auto only attaches to a VPS container that is already running — a stopped or missing one is never provisioned or started, and the bot quietly works as if no cloud computer existed. Choose Cloud to provision or start it. No interactive desktop tunnel is exposed."
+ ? "Auto reuses a running VPS by default. Enable Start VPS automatically to let Auto create or wake its managed container, or choose Cloud to do it explicitly. Open the live desktop securely from the computer panel."
: "Box is the default hosted computer. Choose Self-hosted VPS to use your SSH-configured Linux Docker host."}
diff --git a/src/components/ComputerPanel.tsx b/src/components/ComputerPanel.tsx
index 2087d8920f..3f6928e846 100644
--- a/src/components/ComputerPanel.tsx
+++ b/src/components/ComputerPanel.tsx
@@ -591,11 +591,12 @@ export function ComputerPanel({ bot }: { bot: Bot }) {
}
} catch (e) {
fallbackTab?.close();
+ // Release the bot before waiting on best-effort tunnel cleanup. A sick
+ // SSH process must never leave the agent paused indefinitely.
+ if (tookControl) await requestControl("release").catch(() => {});
if (phase === "ready" && cloudBackend === "vps") {
await api(`/api/bots/${bot.id}/computer/viewer-close`, { method: "POST", body: "{}" }).catch(() => {});
}
- // A failed viewer must not leave the bot's hands paused indefinitely.
- if (tookControl) await requestControl("release").catch(() => {});
setError(e instanceof Error ? e.message : String(e));
} finally {
setPending(null);