@meridiona/meridian-darwin-arm64 1.23.1 → 1.23.3

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.23.1
1
+ 1.23.3
package/bin/meridian CHANGED
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meridiona/meridian-darwin-arm64",
3
- "version": "1.23.1",
3
+ "version": "1.23.3",
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": {
@@ -335,6 +335,25 @@ else
335
335
  fi
336
336
  fi
337
337
 
338
+ # On macOS 26+, install apple-fm-sdk so Apple Intelligence is used instead of
339
+ # downloading a large MLX model. This runs after both venv paths (tarball or uv
340
+ # sync) so the package is available regardless of how the venv was built.
341
+ # apple-fm-sdk only installs on macOS 26+ (links against system frameworks);
342
+ # on older macOS pip will fail gracefully and MLX is used as the fallback.
343
+ _macos_major="$(sw_vers -productVersion 2>/dev/null | cut -d. -f1)"
344
+ if [[ "${_macos_major:-0}" -ge 26 ]]; then
345
+ if "${VENV}/bin/python" -c "import apple_fm_sdk" 2>/dev/null; then
346
+ ok "apple-fm-sdk already installed — Apple Intelligence will be used"
347
+ else
348
+ info "macOS ${_macos_major} detected — installing apple-fm-sdk for Apple Intelligence (no MLX model download needed)…"
349
+ if "${VENV}/bin/pip" install --quiet "apple-fm-sdk" 2>/dev/null; then
350
+ ok "apple-fm-sdk installed — Apple Intelligence will be used"
351
+ else
352
+ warn "apple-fm-sdk install failed — MLX model download will be used instead"
353
+ fi
354
+ fi
355
+ fi
356
+
338
357
  # ── 5. macOS permissions for screenpipe (manual — can't be automated) ────────
339
358
  if [[ "${SKIP_PERMISSIONS}" -eq 0 ]]; then
340
359
  echo "→ screenpipe needs 2 macOS permissions: Screen Recording and Accessibility."
@@ -278,6 +278,31 @@ _MANAGED_SERVER_PID_FILE = Path.home() / ".meridian" / "mlx_lm_server.pid"
278
278
  APPLE_INTELLIGENCE_ID = "apple-intelligence"
279
279
 
280
280
 
281
+ def _apple_intelligence_available() -> bool:
282
+ """Return True only when Apple Intelligence is genuinely usable.
283
+
284
+ Checks three things in order (fail-fast):
285
+ 1. macOS 26+ (the minimum for the Foundation Models API)
286
+ 2. apple_fm_sdk is importable (installed in the venv)
287
+ 3. SystemLanguageModel().is_available() — the on-device model is downloaded
288
+ and Apple Intelligence is enabled in System Settings
289
+
290
+ Any failure → False (graceful degradation to smaller MLX or cloud).
291
+ """
292
+ try:
293
+ macos_major = int(platform.mac_ver()[0].split(".")[0] or "0")
294
+ if macos_major < 26:
295
+ return False
296
+ from apple_fm_sdk import SystemLanguageModel # type: ignore[import]
297
+ available, reason = SystemLanguageModel().is_available()
298
+ if not available:
299
+ log.debug("llm_selector: Apple Intelligence unavailable: %s", reason)
300
+ return bool(available)
301
+ except Exception as exc: # noqa: BLE001
302
+ log.debug("llm_selector: Apple Intelligence probe skipped: %s", exc)
303
+ return False
304
+
305
+
281
306
  def _metal_headroom_gb() -> tuple[float, str]:
282
307
  """Primary memory signal — headroom within Metal's recommended working set.
283
308
 
@@ -448,8 +473,7 @@ def local_infer(system_prompt: str, user_message: str,
448
473
  # Relax budget when screen is locked — user won't feel the latency
449
474
  effective_pct = min(0.8, budget_pct * 1.5) if snap.screen_locked else budget_pct
450
475
 
451
- macos_major = int(platform.mac_ver()[0].split(".")[0] or "0")
452
- apple_intelligence = macos_major >= 26
476
+ apple_intelligence = _apple_intelligence_available()
453
477
 
454
478
  entry = _select_mlx_entry(snap.metal_headroom_gb, effective_pct,
455
479
  snap.thermal_level, apple_intelligence)
@@ -893,8 +917,7 @@ def select_mlx_model_id(
893
917
  span.set_attribute("llm.selected_model", preferred_hf_id or "")
894
918
  return preferred_hf_id
895
919
 
896
- macos_major = int(platform.mac_ver()[0].split(".")[0] or "0")
897
- apple_intelligence = macos_major >= 26
920
+ apple_intelligence = _apple_intelligence_available()
898
921
 
899
922
  try:
900
923
  snap = probe_compute()
@@ -272,6 +272,12 @@ def _get_model() -> Any:
272
272
  return outlines_model
273
273
 
274
274
 
275
+ # Apple Foundation Models has a 4096-token combined context window (input + output).
276
+ # Reserve _MAX_TOKENS (1024) for the response; leave ~3072 tokens for the prompt.
277
+ # At ~4 chars/token that is ~12 000 chars. Cap the user message to stay inside it.
278
+ _APPLE_FM_USER_CHARS = 11_000
279
+
280
+
275
281
  def _classify_apple_fm(messages: list[dict[str, str]]) -> "SessionClassification":
276
282
  """Classify via Apple Foundation Models (non-FSM, JSON parsing with one retry)."""
277
283
  import asyncio
@@ -280,6 +286,15 @@ def _classify_apple_fm(messages: list[dict[str, str]]) -> "SessionClassification
280
286
 
281
287
  system = next((m["content"] for m in messages if m["role"] == "system"), "")
282
288
  user = next((m["content"] for m in messages if m["role"] == "user"), "")
289
+
290
+ # Truncate to stay within the 4096-token context window.
291
+ if len(user) > _APPLE_FM_USER_CHARS:
292
+ log.debug(
293
+ "run_task_linker_mlx: truncating Apple FM user message %d → %d chars",
294
+ len(user), _APPLE_FM_USER_CHARS,
295
+ )
296
+ user = user[:_APPLE_FM_USER_CHARS]
297
+
283
298
  user_with_hint = (
284
299
  user
285
300
  + "\n\nRespond with a JSON object matching the SessionClassification schema. "
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "meridian-agents"
7
- version = "1.23.1"
7
+ version = "1.23.3"
8
8
  description = "Meridian agents — hermes task linking and Jira progress updates for meridian.db"
9
9
  requires-python = ">=3.11"
10
10
  authors = [{ name = "Meridiona" }]
package/ui.tar.gz CHANGED
Binary file