diff --git a/apps/desktop/src/i18n/en.ts b/apps/desktop/src/i18n/en.ts index c2120533743..a607ed93efb 100644 --- a/apps/desktop/src/i18n/en.ts +++ b/apps/desktop/src/i18n/en.ts @@ -798,7 +798,7 @@ export const en: Translations = { namePlaceholder: 'Name your pet', staleBackend: 'Update Hermes to generate pets.', backgroundHint: 'You can close this — Hermes will notify you when it’s done.', - slowProviderHint: 'This can take up to 5 minutes', + slowProviderHint: 'This can take several minutes', genericError: 'Generation failed — try again or pick a suggestion.', referenceImageTooLarge: 'Reference image is too large. Use one under 16 MB.', referenceImageInvalid: 'Could not read that reference image. Try a PNG, JPG, WebP, or GIF.', diff --git a/apps/desktop/src/i18n/ja.ts b/apps/desktop/src/i18n/ja.ts index ba2317b41f1..2f5344e3d67 100644 --- a/apps/desktop/src/i18n/ja.ts +++ b/apps/desktop/src/i18n/ja.ts @@ -916,7 +916,7 @@ export const ja = defineLocale({ namePlaceholder: 'ペットに名前を付ける', staleBackend: 'ペットを生成するには Hermes を更新してください。', backgroundHint: 'このウィンドウは閉じても大丈夫です。完了したら Hermes が通知します。', - slowProviderHint: 'これには最大5分かかることがあります。', + slowProviderHint: '数分かかることがあります', genericError: '生成に失敗しました。もう一度試すか、候補を選んでください。', referenceImageTooLarge: '参照画像が大きすぎます。16 MB 未満の画像を使ってください。', referenceImageInvalid: '参照画像を読み込めませんでした。PNG/JPG/WebP/GIF を試してください。', diff --git a/apps/desktop/src/i18n/zh-hant.ts b/apps/desktop/src/i18n/zh-hant.ts index 8285a9adc0a..439aa0bf5c2 100644 --- a/apps/desktop/src/i18n/zh-hant.ts +++ b/apps/desktop/src/i18n/zh-hant.ts @@ -888,7 +888,7 @@ export const zhHant = defineLocale({ namePlaceholder: '為寵物命名', staleBackend: '請更新 Hermes 以生成寵物。', backgroundHint: '你可以關閉此視窗——完成後 Hermes 會通知你。', - slowProviderHint: '這可能最多需要 5 分鐘。', + slowProviderHint: '這可能需要幾分鐘', genericError: '生成失敗——請重試或選一個建議。', referenceImageTooLarge: '參考圖片過大。請使用小於 16 MB 的圖片。', referenceImageInvalid: '無法讀取該參考圖片。請嘗試 PNG、JPG、WebP 或 GIF。', diff --git a/apps/desktop/src/i18n/zh.ts b/apps/desktop/src/i18n/zh.ts index 90613bd86a5..619f9817b02 100644 --- a/apps/desktop/src/i18n/zh.ts +++ b/apps/desktop/src/i18n/zh.ts @@ -986,7 +986,7 @@ export const zh: Translations = { namePlaceholder: '给宠物起个名字', staleBackend: '请更新 Hermes 以生成宠物。', backgroundHint: '你可以关闭此窗口——完成后 Hermes 会通知你。', - slowProviderHint: '这可能最多需要 5 分钟。', + slowProviderHint: '这可能需要几分钟', genericError: '生成失败——请重试或选择一个建议。', referenceImageTooLarge: '参考图过大。请使用小于 16 MB 的图片。', referenceImageInvalid: '无法读取该参考图。请尝试 PNG、JPG、WebP 或 GIF。', diff --git a/apps/desktop/src/store/pet-generate.ts b/apps/desktop/src/store/pet-generate.ts index 2b7962775aa..5713b04a8a7 100644 --- a/apps/desktop/src/store/pet-generate.ts +++ b/apps/desktop/src/store/pet-generate.ts @@ -22,11 +22,15 @@ import { applyAdoptedPet, type GatewayRequest } from '@/store/pet-gallery' */ // Generation is many grounded image calls — far longer than the default 30s RPC -// timeout. Drafts fan out 4 base looks; hatch fans out ~8 animation rows. Even -// parallelized, a cold provider call is slow, so we give these calls real -// headroom (the bug was "request timed out: pet.generate" on the 30s default). -const GENERATE_TIMEOUT_MS = 240_000 -const HATCH_TIMEOUT_MS = 420_000 +// timeout. Drafts fan out 4 base looks; hatch fans out ~8 animation rows. The +// quality-first default (OpenAI image via OpenRouter) is slow, and each hatch +// row can retry up to 3x (300s/call) across 2 parallel waves, so the absolute +// backend worst case is ~30 min. The hatch ceiling sits above that (1h) so the +// frontend never throws "request timed out" before the backend has actually +// exhausted its own retries — the background-resumable notify path is the real +// UX safety net (the user can close the modal and get pinged on completion). +const GENERATE_TIMEOUT_MS = 420_000 +const HATCH_TIMEOUT_MS = 3_600_000 // Filler words to drop when deriving a default name from a free-text prompt. const NAME_STOPWORDS = new Set([ diff --git a/plugins/image_gen/openrouter/__init__.py b/plugins/image_gen/openrouter/__init__.py index 5b2b105d040..d15aaabd53b 100644 --- a/plugins/image_gen/openrouter/__init__.py +++ b/plugins/image_gen/openrouter/__init__.py @@ -64,7 +64,10 @@ _ASPECT_RATIOS = { # so we never overflow the model's limit. _MAX_REFERENCE_IMAGES = 3 -_REQUEST_TIMEOUT = 180.0 +# Per single image call. The quality-first default (OpenAI image via OpenRouter) +# is genuinely slow — a single cold row can run well past 3 minutes — so give +# each call real headroom before we treat it as hung and fall back / retry. +_REQUEST_TIMEOUT = 300.0 def _load_image_gen_config() -> Dict[str, Any]: diff --git a/scripts/run_tests.sh b/scripts/run_tests.sh index b9f070f09e8..20deae4c9ef 100755 --- a/scripts/run_tests.sh +++ b/scripts/run_tests.sh @@ -74,6 +74,7 @@ exec env -i \ LC_ALL=C.UTF-8 \ PYTHONHASHSEED=0 \ PYTHONDONTWRITEBYTECODE=1 \ + ${HERMES_RUN_SLOW_PET_TESTS:+HERMES_RUN_SLOW_PET_TESTS="$HERMES_RUN_SLOW_PET_TESTS"} \ ${EXTRA_PYTHONPATH:+PYTHONPATH="$EXTRA_PYTHONPATH"} \ ${EXTRA_PYTEST_PLUGINS:+PYTEST_PLUGINS="$EXTRA_PYTEST_PLUGINS"} \ "$PYTHON" "$SCRIPT_DIR/run_tests_parallel.py" "$@" diff --git a/tests/agent/test_pet_generate.py b/tests/agent/test_pet_generate.py index 800f8fa36e8..17d8b24104b 100644 --- a/tests/agent/test_pet_generate.py +++ b/tests/agent/test_pet_generate.py @@ -7,8 +7,18 @@ exercised hermetically. from __future__ import annotations +import os + import pytest +pytestmark = pytest.mark.skipif( + os.environ.get("HERMES_RUN_SLOW_PET_TESTS") != "1", + reason=( + "pet generation image-processing suite is opt-in; run with " + "HERMES_RUN_SLOW_PET_TESTS=1 scripts/run_tests.sh tests/agent/test_pet_generate.py" + ), +) + from agent.pet.generate import atlas PIL = pytest.importorskip("PIL")