55fa4656ff
For redeploying curator while away with nobody to restart the agent: - _process now distinguishes a TRANSPORT error (curator down/redeploying, 5xx, 401/403/408/409/429, or our lease reclaimed mid-flight) from a genuine job fault. On a transport error it hands the job back (best effort) and signals the loop to back off — instead of calling fail(), which would burn the job's server-side attempt budget (MAX_ATTEMPTS=3) and permanently error good jobs across a redeploy. Job-specific 4xx (404 image gone) still fail so they don't re-lease forever. - lease loop retries with capped exponential backoff (poll_idle → 60s) and resets on the first successful lease, so a long outage is gentle and recovery is automatic within ≤60s of curator returning. Sleeps are interruptible so Stop / pool-shrink stays responsive. - AUTO_START env (default on in compose) resumes the worker on container start, so a host reboot / crash-restart (restart: unless-stopped) self-heals with nobody at the desktop. - control UI shows a "waited out" counter + an "curator unreachable, holding work" banner so the recovering state reads as recovery, not failure. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ttrj5P7upUTueSfoJcxEqa
37 lines
1.9 KiB
Python
37 lines
1.9 KiB
Python
"""Agent config, all from env (the control container is configured at run)."""
|
|
import os
|
|
from dataclasses import dataclass
|
|
|
|
|
|
@dataclass
|
|
class Config:
|
|
fc_url: str # base URL of the FabledCurator web service
|
|
token: str # the bearer token from Settings → Tagging → GPU agent
|
|
agent_id: str # identifies this agent's leases
|
|
batch_size: int # jobs a worker leases per round
|
|
concurrency: int # INITIAL parallel workers (tunable live from the UI)
|
|
ccip_model: str # imgutils CCIP model name ("" → imgutils default)
|
|
detector_level: str # imgutils person-detector level: n|s|m|x
|
|
poll_idle_seconds: float # wait between empty leases
|
|
embed_dtype: str # torch dtype for the crop embedder: float16|float32
|
|
embed_model_override: str # force a SigLIP-family model ("" → use the one
|
|
# the server announces in the lease)
|
|
auto_start: bool # start the worker pool on boot (so a container restart
|
|
# resumes processing without anyone clicking Start)
|
|
|
|
@classmethod
|
|
def from_env(cls) -> "Config":
|
|
return cls(
|
|
fc_url=os.environ.get("FC_URL", "http://localhost:8000").rstrip("/"),
|
|
token=os.environ.get("FC_TOKEN", ""),
|
|
agent_id=os.environ.get("AGENT_ID", "desktop-agent"),
|
|
batch_size=int(os.environ.get("BATCH_SIZE", "4")),
|
|
concurrency=int(os.environ.get("CONCURRENCY", "1")),
|
|
ccip_model=os.environ.get("CCIP_MODEL", ""),
|
|
detector_level=os.environ.get("DETECTOR_LEVEL", "m"),
|
|
poll_idle_seconds=float(os.environ.get("POLL_IDLE_SECONDS", "10")),
|
|
embed_dtype=os.environ.get("SIGLIP_DTYPE", "float16"),
|
|
embed_model_override=os.environ.get("EMBED_MODEL_NAME", ""),
|
|
auto_start=os.environ.get("AUTO_START", "").lower() in ("1", "true", "yes"),
|
|
)
|