@meridiona/meridian-darwin-arm64 1.66.1 → 1.67.0
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 +1 -1
- package/bin/meridian +0 -0
- package/bin/meridian-tray +0 -0
- package/package.json +1 -1
- package/services/agents/routes/prefetch.py +86 -8
- package/services/pyproject.toml +1 -1
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.
|
|
1
|
+
1.67.0
|
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.
|
|
3
|
+
"version": "1.67.0",
|
|
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
|
|
35
|
-
#
|
|
36
|
-
#
|
|
37
|
-
#
|
|
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,93 @@ 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. Non-positive
|
|
91
|
+
integers are also rejected for consistency.
|
|
92
|
+
"""
|
|
93
|
+
raw = os.environ.get(name)
|
|
94
|
+
if raw is None:
|
|
95
|
+
return default
|
|
96
|
+
try:
|
|
97
|
+
val = int(raw)
|
|
98
|
+
if val <= 0:
|
|
99
|
+
log.warning(
|
|
100
|
+
"server: ignoring non-positive env override; using default",
|
|
101
|
+
extra={"env_var": name, "raw": raw, "default": default},
|
|
102
|
+
)
|
|
103
|
+
return default
|
|
104
|
+
return val
|
|
105
|
+
except ValueError:
|
|
106
|
+
log.warning(
|
|
107
|
+
"server: ignoring non-integer env override; using default",
|
|
108
|
+
extra={"env_var": name, "raw": raw, "default": default},
|
|
109
|
+
)
|
|
110
|
+
return default
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
# How many times to (re)enter snapshot_download for one model before giving up.
|
|
114
|
+
# Each retry resumes from the on-disk ``.incomplete`` partial (HF Range request),
|
|
115
|
+
# so bytes already pulled are never re-downloaded. Env-overridable for ops.
|
|
116
|
+
_PREFETCH_MAX_ATTEMPTS = _env_positive_int("MERIDIAN_PREFETCH_MAX_ATTEMPTS", 5)
|
|
117
|
+
|
|
118
|
+
|
|
84
119
|
def _download_spec(spec: model_registry.ModelSpec) -> None:
|
|
85
120
|
"""Download one model's weights to the HF cache (no load into memory).
|
|
86
121
|
|
|
87
|
-
|
|
88
|
-
|
|
122
|
+
Forces the classic (non-Xet) transfer path and retries with resume so a
|
|
123
|
+
stalled connection can never wedge the download indefinitely:
|
|
124
|
+
|
|
125
|
+
* **Xet is disabled for the pull.** ``hf_xet`` does its transfer in Rust with
|
|
126
|
+
no per-read timeout and can't be interrupted from Python, so a half-open
|
|
127
|
+
connection to the Xet CAS endpoint hangs forever (observed: a prefetch stuck
|
|
128
|
+
at 57% for 4h on a healthy 16 Mbps link — bytes never resumed). The classic
|
|
129
|
+
path caps every read at ``HF_HUB_DOWNLOAD_TIMEOUT`` (10s) and resumes from the
|
|
130
|
+
``.incomplete`` partial via a Range request, so a stall raises and self-heals
|
|
131
|
+
instead of hanging. On a cold first-run pull of distinct model weights Xet's
|
|
132
|
+
chunk-dedup buys little, so this trades an unused fast-path for a bounded,
|
|
133
|
+
resumable one. (Bonus: the classic path grows the on-disk blob linearly, so
|
|
134
|
+
``/prefetch_status``'s byte-delta speed reads smoothly instead of sitting at 0
|
|
135
|
+
then jumping in bursts as hf_xet flushes reconstructed chunks.)
|
|
136
|
+
* **Bounded retries** re-enter ``snapshot_download`` on any error; each attempt
|
|
137
|
+
resumes from the partial, so transient drops that exhaust the library's own
|
|
138
|
+
per-read retries still converge without re-pulling what's on disk.
|
|
139
|
+
|
|
89
140
|
``mlx_lm.load`` / ``mlx_embeddings.load`` resolve the files straight from the
|
|
90
141
|
cache afterwards. Only disk is touched — the single-slot runtime loads each
|
|
91
|
-
model lazily on first use.
|
|
142
|
+
model lazily on first use. Disabling Xet here is process-global (it flips a
|
|
143
|
+
huggingface_hub module constant), so later in-process model loads inherit the
|
|
144
|
+
same bounded, resumable path — which is what we want on a network where Xet
|
|
145
|
+
stalls.
|
|
92
146
|
"""
|
|
147
|
+
from huggingface_hub import constants as hf_constants
|
|
93
148
|
from huggingface_hub import snapshot_download
|
|
94
|
-
|
|
149
|
+
|
|
150
|
+
# Flip the *module attribute* (re-read per download at file_download.py call
|
|
151
|
+
# sites), NOT the env var: the env is parsed into this constant once at import,
|
|
152
|
+
# so ``os.environ`` here would be a no-op for an already-imported library.
|
|
153
|
+
hf_constants.HF_HUB_DISABLE_XET = True
|
|
154
|
+
|
|
155
|
+
for attempt in range(1, _PREFETCH_MAX_ATTEMPTS + 1):
|
|
156
|
+
try:
|
|
157
|
+
snapshot_download(spec.model_id, allow_patterns=spec.allow_patterns)
|
|
158
|
+
except Exception as exc: # noqa: BLE001 — retry-with-resume, re-raise if exhausted
|
|
159
|
+
log.warning(
|
|
160
|
+
"server: prefetch download attempt failed; will resume from partial",
|
|
161
|
+
extra={
|
|
162
|
+
"model_id": spec.model_id,
|
|
163
|
+
"attempt": attempt,
|
|
164
|
+
"max_attempts": _PREFETCH_MAX_ATTEMPTS,
|
|
165
|
+
"error": str(exc),
|
|
166
|
+
},
|
|
167
|
+
)
|
|
168
|
+
if attempt >= _PREFETCH_MAX_ATTEMPTS:
|
|
169
|
+
raise # all attempts exhausted — surface the active error to _run_prefetch
|
|
170
|
+
time.sleep(min(2**attempt, 30)) # 2s, 4s, 8s, 16s … capped at 30s
|
|
171
|
+
else:
|
|
172
|
+
return # download succeeded
|
|
95
173
|
|
|
96
174
|
|
|
97
175
|
def _run_prefetch(specs: list[model_registry.ModelSpec]) -> None:
|
package/services/pyproject.toml
CHANGED
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "meridian-agents"
|
|
7
|
-
version = "1.
|
|
7
|
+
version = "1.67.0"
|
|
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" }]
|