From 467eaccd59f3c925a0831caefcc090ebb226fecb Mon Sep 17 00:00:00 2001 From: CoolBoy Date: Sat, 15 Aug 2026 19:33:07 +0800 Subject: [PATCH] fix: install git for durable state recovery --- Dockerfile | 4 ++++ README.md | 9 +++++---- modelhub_submmit_api/state_sync.py | 27 +++++++++++++++++---------- modelhub_submmit_api/version.py | 2 +- tests/test_super_agent.py | 14 ++++++++++++++ 5 files changed, 41 insertions(+), 15 deletions(-) diff --git a/Dockerfile b/Dockerfile index 2ce290cb..30fe54ce 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,6 +5,10 @@ ENV PYTHONPATH=/app/modelhub_submmit_api WORKDIR /app +RUN apt-get update \ + && apt-get install -y --no-install-recommends ca-certificates git \ + && rm -rf /var/lib/apt/lists/* + COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt diff --git a/README.md b/README.md index 33d95525..69e53026 100644 --- a/README.md +++ b/README.md @@ -362,18 +362,19 @@ counts fail closed for older candidates, and no startup or periodic cleanup can cancel a task by date. It also keeps unclassified/ambiguous historical failures neutral in GPU/framework success feedback while preserving deterministic OOM and architecture cleanup. -Version `2026.08.15.1` replaces the 70/30 quota with hierarchical success-first +Version `2026.08.15.2` replaces the 70/30 quota with hierarchical success-first routing, dynamically gates models through the official GPU/task/framework/config APIs, enriches ModelScope metadata and model lineage, learns only proven safe config vectors, and adds crash-safe write-ahead state synchronization to the `agent-state` branch. It also exposes `/ready` and extends deterministic cleanup -to officially removed waiting GPU/framework routes. +to officially removed waiting GPU/framework routes. The runtime image installs +Git and CA certificates required by state recovery and synchronization. ## Deploy Create a tag and submit the repository URL plus tag in "我的适配智能体". ```bash -git tag -a agent-v25 -m "ModelHub agent 2026.08.15.1" -git push origin main agent-v25 +git tag -a agent-v26 -m "ModelHub agent 2026.08.15.2" +git push origin main agent-v26 ``` diff --git a/modelhub_submmit_api/state_sync.py b/modelhub_submmit_api/state_sync.py index de1f514e..b1edfddd 100644 --- a/modelhub_submmit_api/state_sync.py +++ b/modelhub_submmit_api/state_sync.py @@ -222,16 +222,23 @@ class StateGitSync: return env def _git(self, *args: str, cwd: Path | None = None, check: bool = True) -> subprocess.CompletedProcess[str]: - result = subprocess.run( - ["git", *args], - cwd=str(cwd or self.project_root), - env=self._git_environment(), - text=True, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - timeout=45, - check=False, - ) + try: + result = subprocess.run( + ["git", *args], + cwd=str(cwd or self.project_root), + env=self._git_environment(), + text=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + timeout=45, + check=False, + ) + except FileNotFoundError as exc: + raise StateSyncError( + "git executable is unavailable; rebuild the service image from the repository Dockerfile" + ) from exc + except subprocess.TimeoutExpired as exc: + raise StateSyncError("git operation timed out after 45 seconds") from exc if check and result.returncode != 0: reason = _safe_text(result.stderr.strip() or result.stdout.strip() or f"git exited {result.returncode}") raise StateSyncError(reason) diff --git a/modelhub_submmit_api/version.py b/modelhub_submmit_api/version.py index 45744503..0cbe3f3e 100644 --- a/modelhub_submmit_api/version.py +++ b/modelhub_submmit_api/version.py @@ -1 +1 @@ -AGENT_VERSION = "2026.08.15.1" +AGENT_VERSION = "2026.08.15.2" diff --git a/tests/test_super_agent.py b/tests/test_super_agent.py index f3d1e843..4abfa277 100644 --- a/tests/test_super_agent.py +++ b/tests/test_super_agent.py @@ -20,6 +20,7 @@ from hf_discovery import HuggingFaceDiscovery, parse_model_card_front_matter # from official_capabilities import OfficialCapabilityRegistry # noqa: E402 from routing_engine import SuccessFirstRoutingEngine # noqa: E402 from state_sync import StateGitSync # noqa: E402 +from state_sync import StateSyncError # noqa: E402 class OfficialClient: @@ -207,6 +208,19 @@ class SuperAgentTests(unittest.TestCase): ) ) + def test_missing_git_has_actionable_state_sync_error(self) -> None: + with tempfile.TemporaryDirectory() as temporary_dir: + manager = StateGitSync( + project_root=Path(temporary_dir), + credentials={"username": "u", "email": "e@example.com", "password": "p"}, + remote="unused", + log_fn=lambda _: None, + ) + with patch("state_sync.subprocess.run", side_effect=FileNotFoundError("git")): + with self.assertRaisesRegex(StateSyncError, "rebuild the service image"): + manager._git("version") + manager.close() + def test_config_patch_requires_repeated_cross_model_success(self) -> None: with tempfile.TemporaryDirectory() as temporary_dir: root = Path(temporary_dir)