feat: cloud update notice

This commit is contained in:
zhom committed 2026-11-06 22:45:25 +04:00
1 parent 86c60aa698
commit 0d69f2b475
15 files changed
+80 -24

No files matched your search

+53 -24
View File
@@ -13228,10 +13228,30 @@ impl McpServer {
/// to do next; a stable code and its parameters are something it can branch
/// on, and it is the same envelope the desktop and the REST API answer with.
fn cloud_error(err: crate::cookie_bot::CookieBotError) -> McpError {
McpError {
code: -32000,
message: err.to_error_json(),
data: None,
Self::cloud_failure(err.to_error_json())
}
/// A cloud failure for an agent. A code with a sentence of its own gets that
/// sentence as the message and the envelope as data; any other code keeps
/// the envelope as the message.
fn cloud_failure(envelope: String) -> McpError {
let parsed = serde_json::from_str::<serde_json::Value>(&envelope).ok();
let sentence = parsed
.as_ref()
.and_then(|value| value.get("code"))
.and_then(|code| code.as_str())
.and_then(cloud_failure_sentence);
match sentence {
Some(text) => McpError {
code: -32000,
message: text.to_string(),
data: parsed,
},
None => McpError {
code: -32000,
message: envelope,
data: None,
},
}
}
@@ -13310,11 +13330,7 @@ impl McpServer {
let outcome = crate::remote_session::start_remote_session(app, &profile, url)
.await
.map_err(|e| McpError {
code: -32000,
message: e.to_error_json(),
data: None,
})?;
.map_err(|e| Self::cloud_failure(e.to_error_json()))?;
Self::json_content(&outcome)
}
@@ -13325,22 +13341,14 @@ impl McpServer {
let session_id = Self::require_str(arguments, "session_id")?;
let outcome = crate::remote_session::end_remote_session(session_id)
.await
.map_err(|e| McpError {
code: -32000,
message: e.to_error_json(),
data: None,
})?;
.map_err(|e| Self::cloud_failure(e.to_error_json()))?;
Self::json_content(&outcome)
}
async fn handle_list_remote_sessions() -> Result<serde_json::Value, McpError> {
let sessions = crate::remote_session::list_remote_sessions()
.await
.map_err(|e| McpError {
code: -32000,
message: e.to_error_json(),
data: None,
})?;
.map_err(|e| Self::cloud_failure(e.to_error_json()))?;
Self::json_content(&sessions)
}
@@ -13350,11 +13358,7 @@ impl McpServer {
let session_id = Self::require_str(arguments, "session_id")?;
let state = crate::remote_session::get_remote_session(session_id)
.await
.map_err(|e| McpError {
code: -32000,
message: e.to_error_json(),
data: None,
})?;
.map_err(|e| Self::cloud_failure(e.to_error_json()))?;
Self::json_content(&state)
}
@@ -13562,6 +13566,16 @@ impl McpServer {
static MCP_SERVER: std::sync::LazyLock<McpServer> = std::sync::LazyLock::new(McpServer::new);
/// What an agent reads for a cloud code it should relay to the person.
fn cloud_failure_sentence(code: &str) -> Option<&'static str> {
match code {
"CLOUD_BROWSER_UPDATING" => Some(
"The cloud browser is updating to this profile's Wayfern version. Try again in a few minutes.",
),
_ => None,
}
}
#[cfg(test)]
#[path = "mcp_server_browser_tests.rs"]
mod browser_tests;
@@ -13570,6 +13584,21 @@ mod browser_tests;
mod tests {
use super::*;
#[test]
fn a_cloud_update_refusal_reads_as_a_sentence_with_its_envelope() {
let envelope = r#"{"code":"CLOUD_BROWSER_UPDATING","params":{"cloudVersion":"1.0.0.1","profileVersion":"1.0.0.2"}}"#;
let error = McpServer::cloud_failure(envelope.to_string());
assert!(error.message.starts_with("The cloud browser is updating"));
let data = error.data.expect("envelope as data");
assert_eq!(data["code"], "CLOUD_BROWSER_UPDATING");
assert_eq!(data["params"]["profileVersion"], "1.0.0.2");
let other = r#"{"code":"REMOTE_NO_CAPACITY"}"#;
let error = McpServer::cloud_failure(other.to_string());
assert_eq!(error.message, other);
assert!(error.data.is_none());
}
#[test]
fn an_engine_plan_refusal_is_explained_by_a_device_refusal() {
let engine = || {
+1
View File
@@ -659,6 +659,7 @@ export const OUTCOME_KEYS: Record<string, string> = {
quota_exhausted: "cookieBot.outcome.quotaExhausted",
profile_locked: "cookieBot.outcome.profileLocked",
no_capacity: "cookieBot.outcome.noCapacity",
cloud_browser_updating: "cookieBot.outcome.cloudBrowserUpdating",
manager_error: "cookieBot.outcome.managerError",
budget_exceeded: "cookieBot.outcome.budgetExceeded",
// The commonest real outcome of the five missing ones, and it was showing
+2
View File
@@ -2689,6 +2689,7 @@
"cloudNotSignedIn": "Melden Sie sich bei Ihrem Donut Browser-Konto an, um dies zu nutzen.",
"cloudUnreachable": "Die Server von Donut Browser sind nicht erreichbar. Prüfen Sie Ihre Verbindung und versuchen Sie es erneut.",
"cloudRequestFailed": "Die Anfrage ist fehlgeschlagen. Bitte versuchen Sie es gleich noch einmal.",
"cloudBrowserUpdating": "Der Cloud-Browser wird auf Ihre Wayfern-Version aktualisiert. Versuchen Sie es in ein paar Minuten erneut.",
"remoteRateLimited": "Zu viele Anfragen. Warten Sie einen Moment und versuchen Sie es erneut.",
"remoteNoCapacity": "Derzeit ist kein entfernter Host frei. Versuchen Sie es in einigen Minuten erneut.",
"remoteNotEntitled": "Ihr Tarif umfasst keine entfernte Ausführung.",
@@ -3721,6 +3722,7 @@
"quotaExhausted": "Remote-Stunden aufgebraucht",
"profileLocked": "Das Profil war an anderer Stelle geöffnet",
"noCapacity": "Kein Rechner war frei",
"cloudBrowserUpdating": "Der Cloud-Browser wurde gerade auf Ihre Wayfern-Version aktualisiert",
"managerError": "Die Remote-Rechner konnten den Browser nicht starten",
"budgetExceeded": "Das Zeitbudget des Durchlaufs war aufgebraucht",
"browsingIncomplete": "Der Browser wurde geöffnet, aber das Surfen wurde nicht abgeschlossen",
+2
View File
@@ -2689,6 +2689,7 @@
"cloudNotSignedIn": "Sign in to your Donut Browser account to use this.",
"cloudUnreachable": "Could not reach Donut Browser's servers. Check your connection and try again.",
"cloudRequestFailed": "The request failed. Please try again in a moment.",
"cloudBrowserUpdating": "The cloud browser is updating to your Wayfern version. Try again in a few minutes.",
"remoteRateLimited": "Too many requests. Wait a moment and try again.",
"remoteNoCapacity": "No remote host is free right now. Try again in a few minutes.",
"remoteNotEntitled": "Your plan does not include remote execution.",
@@ -3721,6 +3722,7 @@
"quotaExhausted": "Remote hours used up",
"profileLocked": "The profile was open somewhere else",
"noCapacity": "No machine was free",
"cloudBrowserUpdating": "The cloud browser was updating to your Wayfern version",
"managerError": "The fleet could not start the browser",
"budgetExceeded": "The run's time budget ran out",
"browsingIncomplete": "The browser opened but the browsing did not finish",
+2
View File
@@ -2708,6 +2708,7 @@
"cloudNotSignedIn": "Inicia sesión en tu cuenta de Donut Browser para usar esto.",
"cloudUnreachable": "No se pudo contactar con los servidores de Donut Browser. Comprueba tu conexión e inténtalo de nuevo.",
"cloudRequestFailed": "La solicitud falló. Inténtalo de nuevo en un momento.",
"cloudBrowserUpdating": "El navegador en la nube se está actualizando a tu versión de Wayfern. Vuelve a intentarlo en unos minutos.",
"remoteRateLimited": "Demasiadas solicitudes. Espera un momento e inténtalo de nuevo.",
"remoteNoCapacity": "Ahora mismo no hay ninguna máquina remota libre. Inténtalo de nuevo en unos minutos.",
"remoteNotEntitled": "Tu plan no incluye la ejecución remota.",
@@ -3759,6 +3760,7 @@
"quotaExhausted": "Horas remotas agotadas",
"profileLocked": "El perfil estaba abierto en otro lugar",
"noCapacity": "No había ninguna máquina libre",
"cloudBrowserUpdating": "El navegador en la nube se estaba actualizando a tu versión de Wayfern",
"managerError": "La flota no pudo iniciar el navegador",
"budgetExceeded": "Se agotó el tiempo previsto para la ejecución",
"browsingIncomplete": "El navegador se abrió, pero la navegación no terminó",
+2
View File
@@ -2708,6 +2708,7 @@
"cloudNotSignedIn": "Connectez-vous à votre compte Donut Browser pour utiliser cette fonction.",
"cloudUnreachable": "Impossible de joindre les serveurs de Donut Browser. Vérifiez votre connexion et réessayez.",
"cloudRequestFailed": "La requête a échoué. Réessayez dans un instant.",
"cloudBrowserUpdating": "Le navigateur cloud se met à jour vers votre version de Wayfern. Réessayez dans quelques minutes.",
"remoteRateLimited": "Trop de requêtes. Patientez un instant et réessayez.",
"remoteNoCapacity": "Aucune machine distante n'est libre pour le moment. Réessayez dans quelques minutes.",
"remoteNotEntitled": "Votre forfait n'inclut pas l'exécution à distance.",
@@ -3759,6 +3760,7 @@
"quotaExhausted": "Heures distantes épuisées",
"profileLocked": "Le profil était ouvert ailleurs",
"noCapacity": "Aucune machine n'était libre",
"cloudBrowserUpdating": "Le navigateur cloud se mettait à jour vers votre version de Wayfern",
"managerError": "La flotte n'a pas pu démarrer le navigateur",
"budgetExceeded": "Le temps prévu pour l'exécution est épuisé",
"browsingIncomplete": "Le navigateur s'est ouvert mais la navigation n'est pas allée à son terme",
+2
View File
@@ -2689,6 +2689,7 @@
"cloudNotSignedIn": "この機能を使うには Donut Browser アカウントにサインインしてください。",
"cloudUnreachable": "Donut Browser のサーバーに接続できませんでした。接続を確認してもう一度お試しください。",
"cloudRequestFailed": "リクエストに失敗しました。しばらくしてからもう一度お試しください。",
"cloudBrowserUpdating": "クラウドブラウザーをお使いの Wayfern のバージョンに更新しています。数分後にもう一度お試しください。",
"remoteRateLimited": "リクエストが多すぎます。少し待ってからもう一度お試しください。",
"remoteNoCapacity": "現在空いているリモートマシンがありません。数分後にもう一度お試しください。",
"remoteNotEntitled": "ご利用のプランにはリモート実行が含まれていません。",
@@ -3721,6 +3722,7 @@
"quotaExhausted": "リモート時間を使い切りました",
"profileLocked": "プロファイルが別の場所で開かれていました",
"noCapacity": "空きマシンがありませんでした",
"cloudBrowserUpdating": "クラウドブラウザーをお使いの Wayfern のバージョンに更新中でした",
"managerError": "フリートがブラウザーを起動できませんでした",
"budgetExceeded": "実行の持ち時間を使い切りました",
"browsingIncomplete": "ブラウザーは起動しましたが、巡回が完了しませんでした",
+2
View File
@@ -2689,6 +2689,7 @@
"cloudNotSignedIn": "이 기능을 사용하려면 Donut Browser 계정에 로그인하세요.",
"cloudUnreachable": "Donut Browser 서버에 연결하지 못했습니다. 연결 상태를 확인하고 다시 시도하세요.",
"cloudRequestFailed": "요청이 실패했습니다. 잠시 후 다시 시도하세요.",
"cloudBrowserUpdating": "클라우드 브라우저를 사용 중인 Wayfern 버전으로 업데이트하고 있습니다. 몇 분 후에 다시 시도하세요.",
"remoteRateLimited": "요청이 너무 많습니다. 잠시 기다렸다가 다시 시도하세요.",
"remoteNoCapacity": "지금은 사용 가능한 원격 머신이 없습니다. 몇 분 후에 다시 시도하세요.",
"remoteNotEntitled": "현재 요금제에는 원격 실행이 포함되어 있지 않습니다.",
@@ -3721,6 +3722,7 @@
"quotaExhausted": "원격 시간을 모두 사용했습니다",
"profileLocked": "프로필이 다른 곳에서 열려 있었습니다",
"noCapacity": "여유 머신이 없었습니다",
"cloudBrowserUpdating": "클라우드 브라우저를 사용 중인 Wayfern 버전으로 업데이트하는 중이었습니다",
"managerError": "플릿이 브라우저를 시작하지 못했습니다",
"budgetExceeded": "실행 시간 예산이 소진되었습니다",
"browsingIncomplete": "브라우저는 열렸지만 탐색이 끝나지 않았습니다",
+2
View File
@@ -2708,6 +2708,7 @@
"cloudNotSignedIn": "Entre na sua conta do Donut Browser para usar este recurso.",
"cloudUnreachable": "Não foi possível contatar os servidores do Donut Browser. Verifique sua conexão e tente novamente.",
"cloudRequestFailed": "A solicitação falhou. Tente novamente em instantes.",
"cloudBrowserUpdating": "O navegador na nuvem está sendo atualizado para a sua versão do Wayfern. Tente novamente em alguns minutos.",
"remoteRateLimited": "Solicitações demais. Aguarde um momento e tente novamente.",
"remoteNoCapacity": "Nenhuma máquina remota está livre agora. Tente novamente em alguns minutos.",
"remoteNotEntitled": "Seu plano não inclui execução remota.",
@@ -3759,6 +3760,7 @@
"quotaExhausted": "Horas remotas esgotadas",
"profileLocked": "O perfil estava aberto noutro lugar",
"noCapacity": "Nenhuma máquina estava livre",
"cloudBrowserUpdating": "O navegador na nuvem estava sendo atualizado para a sua versão do Wayfern",
"managerError": "A frota não conseguiu iniciar o navegador",
"budgetExceeded": "O tempo previsto para a execução acabou",
"browsingIncomplete": "O navegador abriu, mas a navegação não terminou",
+2
View File
@@ -2727,6 +2727,7 @@
"cloudNotSignedIn": "Войдите в аккаунт Donut Browser, чтобы использовать эту функцию.",
"cloudUnreachable": "Не удалось связаться с серверами Donut Browser. Проверьте подключение и попробуйте снова.",
"cloudRequestFailed": "Запрос не удался. Попробуйте ещё раз через минуту.",
"cloudBrowserUpdating": "Облачный браузер обновляется до вашей версии Wayfern. Повторите попытку через несколько минут.",
"remoteRateLimited": "Слишком много запросов. Подождите немного и попробуйте снова.",
"remoteNoCapacity": "Сейчас нет свободных удалённых машин. Попробуйте через несколько минут.",
"remoteNotEntitled": "Ваш тариф не включает удалённый запуск.",
@@ -3799,6 +3800,7 @@
"quotaExhausted": "Удалённые часы израсходованы",
"profileLocked": "Профиль был открыт в другом месте",
"noCapacity": "Свободных машин не было",
"cloudBrowserUpdating": "Облачный браузер обновлялся до вашей версии Wayfern",
"managerError": "Флот не смог запустить браузер",
"budgetExceeded": "Отведённое на запуск время закончилось",
"browsingIncomplete": "Браузер открылся, но обход сайтов не завершился",
+2
View File
@@ -2689,6 +2689,7 @@
"cloudNotSignedIn": "Bunu kullanmak için Donut Browser hesabınıza giriş yapın.",
"cloudUnreachable": "Donut Browser sunucularına ulaşılamadı. Bağlantınızı kontrol edip tekrar deneyin.",
"cloudRequestFailed": "İstek başarısız oldu. Birazdan tekrar deneyin.",
"cloudBrowserUpdating": "Bulut tarayıcısı Wayfern sürümünüze güncelleniyor. Birkaç dakika sonra tekrar deneyin.",
"remoteRateLimited": "Çok fazla istek. Biraz bekleyip tekrar deneyin.",
"remoteNoCapacity": "Şu anda boş uzak makine yok. Birkaç dakika sonra tekrar deneyin.",
"remoteNotEntitled": "Planınız uzaktan çalıştırmayı içermiyor.",
@@ -3721,6 +3722,7 @@
"quotaExhausted": "Uzak saatler tükendi",
"profileLocked": "Profil başka bir yerde açıktı",
"noCapacity": "Boş makine yoktu",
"cloudBrowserUpdating": "Bulut tarayıcısı Wayfern sürümünüze güncelleniyordu",
"managerError": "Filo tarayıcıyı başlatamadı",
"budgetExceeded": "Çalışmanın süresi doldu",
"browsingIncomplete": "Tarayıcı açıldı ama gezinme tamamlanmadı",
+2
View File
@@ -2689,6 +2689,7 @@
"cloudNotSignedIn": "Hãy đăng nhập tài khoản Donut Browser để dùng tính năng này.",
"cloudUnreachable": "Không kết nối được tới máy chủ Donut Browser. Hãy kiểm tra kết nối và thử lại.",
"cloudRequestFailed": "Yêu cầu thất bại. Hãy thử lại sau giây lát.",
"cloudBrowserUpdating": "Trình duyệt đám mây đang cập nhật lên phiên bản Wayfern của bạn. Hãy thử lại sau vài phút.",
"remoteRateLimited": "Quá nhiều yêu cầu. Hãy đợi một lát rồi thử lại.",
"remoteNoCapacity": "Hiện không có máy từ xa nào rảnh. Hãy thử lại sau vài phút.",
"remoteNotEntitled": "Gói của bạn không bao gồm chạy từ xa.",
@@ -3721,6 +3722,7 @@
"quotaExhausted": "Đã dùng hết số giờ từ xa",
"profileLocked": "Hồ sơ đang mở ở nơi khác",
"noCapacity": "Không có máy nào rảnh",
"cloudBrowserUpdating": "Trình duyệt đám mây đang cập nhật lên phiên bản Wayfern của bạn",
"managerError": "Cụm máy không khởi động được trình duyệt",
"budgetExceeded": "Đã hết thời lượng dành cho lần chạy",
"browsingIncomplete": "Trình duyệt đã mở nhưng phiên duyệt chưa hoàn tất",
+2
View File
@@ -2689,6 +2689,7 @@
"cloudNotSignedIn": "请先登录你的 Donut Browser 账号再使用此功能。",
"cloudUnreachable": "无法连接 Donut Browser 服务器。请检查网络后重试。",
"cloudRequestFailed": "请求失败。请稍后再试。",
"cloudBrowserUpdating": "云端浏览器正在更新到你的 Wayfern 版本。请几分钟后再试。",
"remoteRateLimited": "请求过于频繁。请稍候再试。",
"remoteNoCapacity": "当前没有空闲的远程机器。请几分钟后再试。",
"remoteNotEntitled": "你的套餐不包含远程运行。",
@@ -3721,6 +3722,7 @@
"quotaExhausted": "远程时长已用完",
"profileLocked": "该配置文件已在别处打开",
"noCapacity": "没有空闲机器",
"cloudBrowserUpdating": "云端浏览器当时正在更新到你的 Wayfern 版本",
"managerError": "机器集群未能启动浏览器",
"budgetExceeded": "本次运行的时长预算已用完",
"browsingIncomplete": "浏览器已启动,但浏览未完成",
+3
View File
@@ -190,6 +190,7 @@ export type BackendErrorCode =
| "CLOUD_NOT_SIGNED_IN"
| "CLOUD_UNREACHABLE"
| "CLOUD_REQUEST_FAILED"
| "CLOUD_BROWSER_UPDATING"
| "REMOTE_RATE_LIMITED"
| "REMOTE_NO_CAPACITY"
// The deployment has no fleet credential at all, which is not the same as a
@@ -949,6 +950,8 @@ export function translateBackendError(t: TFunction, err: unknown): string {
return t("backendErrors.cloudUnreachable");
case "CLOUD_REQUEST_FAILED":
return t("backendErrors.cloudRequestFailed");
case "CLOUD_BROWSER_UPDATING":
return t("backendErrors.cloudBrowserUpdating");
case "REMOTE_RATE_LIMITED":
return t("backendErrors.remoteRateLimited");
case "REMOTE_NO_CAPACITY": {
+1
View File
@@ -42,6 +42,7 @@ const SERVER_OUTCOME_CODES = [
"browsing_incomplete",
"budget_exceeded",
"cancelled_by_user",
"cloud_browser_updating",
"encrypted_sync",
"manager_error",
"no_capacity",