@meridiona/meridian-darwin-arm64 1.66.1 → 1.66.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/VERSION CHANGED
@@ -1 +1 @@
1
- 1.66.1
1
+ 1.66.2
package/bin/meridian CHANGED
Binary file
package/bin/meridian-tray CHANGED
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meridiona/meridian-darwin-arm64",
3
- "version": "1.66.1",
3
+ "version": "1.66.2",
4
4
  "description": "Prebuilt Meridian app for macOS arm64 (daemon binary + dashboard + Python services). Installed via @meridiona/meridian.",
5
5
  "homepage": "https://github.com/Meridiona/meridian",
6
6
  "repository": {
@@ -16,6 +16,7 @@ from __future__ import annotations
16
16
 
17
17
  import asyncio
18
18
  import logging
19
+ import os
19
20
  import threading
20
21
  import time
21
22
  from pathlib import Path
@@ -31,10 +32,11 @@ log = logging.getLogger("agents.server")
31
32
  router = APIRouter()
32
33
 
33
34
  # Speed is derived from the growth of on-disk `received` between /prefetch_status
34
- # polls — NOT from a tqdm hook. hf_xet (the Xet accelerator these models use) does
35
- # its download in Rust and bypasses the classic tqdm bar, so a tqdm_class never
36
- # fires; the byte-delta approach works for any backend. Stored as a dict so both
37
- # functions can mutate it in-place without `global` declarations.
35
+ # polls — NOT from a tqdm hook (a tqdm_class override never fires reliably across
36
+ # backends). The byte-delta approach is backend-agnostic; with Xet disabled for the
37
+ # prefetch (see `_download_spec`) the classic path grows the blob linearly, so this
38
+ # now reads as a smooth rate rather than the 0-then-burst pattern hf_xet produced.
39
+ # Stored as a dict so both functions can mutate it in-place without `global`s.
38
40
  _speed_state: dict[str, float | int] = {"recv": 0, "ts": 0.0}
39
41
 
40
42
 
@@ -81,17 +83,84 @@ def _spec_total_bytes(spec: model_registry.ModelSpec) -> int:
81
83
  return total
82
84
 
83
85
 
86
+ def _env_positive_int(name: str, default: int) -> int:
87
+ """Read a positive-int env override, falling back to `default` on bad input.
88
+
89
+ Parsed at import, so a non-integer value (operator typo) must degrade to the
90
+ default rather than raise ValueError and brick MLX-server startup.
91
+ """
92
+ raw = os.environ.get(name)
93
+ if raw is None:
94
+ return default
95
+ try:
96
+ return max(1, int(raw))
97
+ except ValueError:
98
+ log.warning(
99
+ "server: ignoring non-integer env override; using default",
100
+ extra={"env_var": name, "raw": raw, "default": default},
101
+ )
102
+ return default
103
+
104
+
105
+ # How many times to (re)enter snapshot_download for one model before giving up.
106
+ # Each retry resumes from the on-disk ``.incomplete`` partial (HF Range request),
107
+ # so bytes already pulled are never re-downloaded. Env-overridable for ops.
108
+ _PREFETCH_MAX_ATTEMPTS = _env_positive_int("MERIDIAN_PREFETCH_MAX_ATTEMPTS", 5)
109
+
110
+
84
111
  def _download_spec(spec: model_registry.ModelSpec) -> None:
85
112
  """Download one model's weights to the HF cache (no load into memory).
86
113
 
87
- All specs go through ``snapshot_download`` (filtered to the spec's
88
- allow_patterns); ``hf-xet`` transparently accelerates the Xet-backed transfers.
114
+ Forces the classic (non-Xet) transfer path and retries with resume so a
115
+ stalled connection can never wedge the download indefinitely:
116
+
117
+ * **Xet is disabled for the pull.** ``hf_xet`` does its transfer in Rust with
118
+ no per-read timeout and can't be interrupted from Python, so a half-open
119
+ connection to the Xet CAS endpoint hangs forever (observed: a prefetch stuck
120
+ at 57% for 4h on a healthy 16 Mbps link — bytes never resumed). The classic
121
+ path caps every read at ``HF_HUB_DOWNLOAD_TIMEOUT`` (10s) and resumes from the
122
+ ``.incomplete`` partial via a Range request, so a stall raises and self-heals
123
+ instead of hanging. On a cold first-run pull of distinct model weights Xet's
124
+ chunk-dedup buys little, so this trades an unused fast-path for a bounded,
125
+ resumable one. (Bonus: the classic path grows the on-disk blob linearly, so
126
+ ``/prefetch_status``'s byte-delta speed reads smoothly instead of sitting at 0
127
+ then jumping in bursts as hf_xet flushes reconstructed chunks.)
128
+ * **Bounded retries** re-enter ``snapshot_download`` on any error; each attempt
129
+ resumes from the partial, so transient drops that exhaust the library's own
130
+ per-read retries still converge without re-pulling what's on disk.
131
+
89
132
  ``mlx_lm.load`` / ``mlx_embeddings.load`` resolve the files straight from the
90
133
  cache afterwards. Only disk is touched — the single-slot runtime loads each
91
- model lazily on first use.
134
+ model lazily on first use. Disabling Xet here is process-global (it flips a
135
+ huggingface_hub module constant), so later in-process model loads inherit the
136
+ same bounded, resumable path — which is what we want on a network where Xet
137
+ stalls.
92
138
  """
139
+ from huggingface_hub import constants as hf_constants
93
140
  from huggingface_hub import snapshot_download
94
- snapshot_download(spec.model_id, allow_patterns=spec.allow_patterns)
141
+
142
+ # Flip the *module attribute* (re-read per download at file_download.py call
143
+ # sites), NOT the env var: the env is parsed into this constant once at import,
144
+ # so ``os.environ`` here would be a no-op for an already-imported library.
145
+ hf_constants.HF_HUB_DISABLE_XET = True
146
+
147
+ for attempt in range(1, _PREFETCH_MAX_ATTEMPTS + 1):
148
+ try:
149
+ snapshot_download(spec.model_id, allow_patterns=spec.allow_patterns)
150
+ return
151
+ except Exception as exc: # noqa: BLE001 — retry-with-resume, re-raise if exhausted
152
+ log.warning(
153
+ "server: prefetch download attempt failed; will resume from partial",
154
+ extra={
155
+ "model_id": spec.model_id,
156
+ "attempt": attempt,
157
+ "max_attempts": _PREFETCH_MAX_ATTEMPTS,
158
+ "error": str(exc),
159
+ },
160
+ )
161
+ if attempt >= _PREFETCH_MAX_ATTEMPTS:
162
+ raise # all attempts exhausted — surface the active error to _run_prefetch
163
+ time.sleep(min(2**attempt, 30)) # 2s, 4s, 8s, 16s … capped at 30s
95
164
 
96
165
 
97
166
  def _run_prefetch(specs: list[model_registry.ModelSpec]) -> None:
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "meridian-agents"
7
- version = "1.66.1"
7
+ version = "1.66.2"
8
8
  description = "Meridian agents — MLX classifier server and Jira worklog synthesis for meridian.db"
9
9
  requires-python = ">=3.11"
10
10
  authors = [{ name = "Meridiona" }]