fix: background task media delivery + vision download timeout (#3919)
* feat(telegram): add webhook mode as alternative to polling When TELEGRAM_WEBHOOK_URL is set, the adapter starts an HTTP webhook server (via python-telegram-bot's start_webhook()) instead of long polling. This enables cloud platforms like Fly.io and Railway to auto-wake suspended machines on inbound HTTP traffic. Polling remains the default — no behavior change unless the env var is set. Env vars: TELEGRAM_WEBHOOK_URL Public HTTPS URL for Telegram to push to TELEGRAM_WEBHOOK_PORT Local listen port (default 8443) TELEGRAM_WEBHOOK_SECRET Secret token for update verification Cherry-picked and adapted from PR #2022 by SHL0MS. Preserved all current main enhancements (network error recovery, polling conflict detection, DM topics setup). Co-authored-by: SHL0MS <SHL0MS@users.noreply.github.com> * fix: send_document call in background task delivery + vision download timeout Two fixes salvaged from PR #2269 by amethystani: 1. gateway/run.py: adapter.send_file() → adapter.send_document() send_file() doesn't exist on BasePlatformAdapter. Background task media files were silently never delivered (AttributeError swallowed by except Exception: pass). 2. tools/vision_tools.py: configurable image download timeout via HERMES_VISION_DOWNLOAD_TIMEOUT env var (default 30s), plus guard against raise None when max_retries=0. The third fix in #2269 (opencode-go auth config) was already resolved on main. Co-authored-by: amethystani <amethystani@users.noreply.github.com> --------- Co-authored-by: SHL0MS <SHL0MS@users.noreply.github.com> Co-authored-by: amethystani <amethystani@users.noreply.github.com>
This commit is contained in:
@@ -324,6 +324,9 @@ compression:
|
||||
# vision:
|
||||
# provider: "auto"
|
||||
# model: "" # e.g. "google/gemini-2.5-flash", "openai/gpt-4o"
|
||||
# timeout: 30 # LLM API call timeout (seconds)
|
||||
# download_timeout: 30 # Image HTTP download timeout (seconds)
|
||||
# # Increase for slow connections or self-hosted image servers
|
||||
#
|
||||
# # Web page scraping / summarization + browser page text extraction
|
||||
# web_extract:
|
||||
|
||||
@@ -3891,7 +3891,7 @@ class GatewayRunner:
|
||||
# Send media files
|
||||
for media_path in (media_files or []):
|
||||
try:
|
||||
await adapter.send_file(
|
||||
await adapter.send_document(
|
||||
chat_id=source.chat_id,
|
||||
file_path=media_path,
|
||||
)
|
||||
|
||||
@@ -223,7 +223,8 @@ DEFAULT_CONFIG = {
|
||||
"model": "", # e.g. "google/gemini-2.5-flash", "gpt-4o"
|
||||
"base_url": "", # direct OpenAI-compatible endpoint (takes precedence over provider)
|
||||
"api_key": "", # API key for base_url (falls back to OPENAI_API_KEY)
|
||||
"timeout": 30, # seconds — increase for slow local vision models
|
||||
"timeout": 30, # seconds — LLM API call timeout; increase for slow local vision models
|
||||
"download_timeout": 30, # seconds — image HTTP download timeout; increase for slow connections
|
||||
},
|
||||
"web_extract": {
|
||||
"provider": "auto",
|
||||
|
||||
@@ -45,6 +45,28 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
_debug = DebugSession("vision_tools", env_var="VISION_TOOLS_DEBUG")
|
||||
|
||||
# Configurable HTTP download timeout for _download_image().
|
||||
# Separate from auxiliary.vision.timeout which governs the LLM API call.
|
||||
# Resolution: config.yaml auxiliary.vision.download_timeout → env var → 30s default.
|
||||
def _resolve_download_timeout() -> float:
|
||||
env_val = os.getenv("HERMES_VISION_DOWNLOAD_TIMEOUT", "").strip()
|
||||
if env_val:
|
||||
try:
|
||||
return float(env_val)
|
||||
except ValueError:
|
||||
pass
|
||||
try:
|
||||
from hermes_cli.config import load_config
|
||||
cfg = load_config()
|
||||
val = cfg.get("auxiliary", {}).get("vision", {}).get("download_timeout")
|
||||
if val is not None:
|
||||
return float(val)
|
||||
except Exception:
|
||||
pass
|
||||
return 30.0
|
||||
|
||||
_VISION_DOWNLOAD_TIMEOUT = _resolve_download_timeout()
|
||||
|
||||
|
||||
def _validate_image_url(url: str) -> bool:
|
||||
"""
|
||||
@@ -146,7 +168,7 @@ async def _download_image(image_url: str, destination: Path, max_retries: int =
|
||||
# Enable follow_redirects to handle image CDNs that redirect (e.g., Imgur, Picsum)
|
||||
# SSRF: event_hooks validates each redirect target against private IP ranges
|
||||
async with httpx.AsyncClient(
|
||||
timeout=30.0,
|
||||
timeout=_VISION_DOWNLOAD_TIMEOUT,
|
||||
follow_redirects=True,
|
||||
event_hooks={"response": [_ssrf_redirect_guard]},
|
||||
) as client:
|
||||
@@ -183,6 +205,10 @@ async def _download_image(image_url: str, destination: Path, max_retries: int =
|
||||
exc_info=True,
|
||||
)
|
||||
|
||||
if last_error is None:
|
||||
raise RuntimeError(
|
||||
f"_download_image exited retry loop without attempting (max_retries={max_retries})"
|
||||
)
|
||||
raise last_error
|
||||
|
||||
|
||||
|
||||
@@ -1018,7 +1018,8 @@ auxiliary:
|
||||
model: "" # e.g. "openai/gpt-4o", "google/gemini-2.5-flash"
|
||||
base_url: "" # Custom OpenAI-compatible endpoint (overrides provider)
|
||||
api_key: "" # API key for base_url (falls back to OPENAI_API_KEY)
|
||||
timeout: 30 # seconds — increase for slow local vision models
|
||||
timeout: 30 # seconds — LLM API call; increase for slow local vision models
|
||||
download_timeout: 30 # seconds — image HTTP download; increase for slow connections
|
||||
|
||||
# Web page summarization + browser page text extraction
|
||||
web_extract:
|
||||
@@ -1042,7 +1043,7 @@ auxiliary:
|
||||
```
|
||||
|
||||
:::tip
|
||||
Each auxiliary task has a configurable `timeout` (in seconds). Defaults: vision 30s, web_extract 30s, approval 30s, compression 120s. Increase these if you use slow local models for auxiliary tasks.
|
||||
Each auxiliary task has a configurable `timeout` (in seconds). Defaults: vision 30s, web_extract 30s, approval 30s, compression 120s. Increase these if you use slow local models for auxiliary tasks. Vision also has a separate `download_timeout` (default 30s) for the HTTP image download — increase this for slow connections or self-hosted image servers.
|
||||
:::
|
||||
|
||||
:::info
|
||||
|
||||
Reference in New Issue
Block a user