Unverified Commit 846c5bb7 authored by kirillrdy's avatar kirillrdy Committed by GitHub
Browse files

exo: 0.0.14-alpha -> 1.0.62 (#477442)

parents b38848f4 02527735
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
diff --git a/src/exo/utils/dashboard_path.py b/src/exo/utils/dashboard_path.py
index b5ce9c04..ec60ef4a 100644
--- a/src/exo/utils/dashboard_path.py
+++ b/src/exo/utils/dashboard_path.py
@@ -5,11 +5,7 @@ from typing import cast
 
 
 def find_dashboard() -> Path:
-    dashboard = (
-        _find_dashboard_in_env()
-        or _find_dashboard_in_repo()
-        or _find_dashboard_in_bundle()
-    )
+    dashboard = "@dashboard@"
     if not dashboard:
         raise FileNotFoundError(
             "Unable to locate dashboard assets - make sure the dashboard has been built, or export DASHBOARD_DIR if you've built the dashboard elsewhere."
+29 −0
Original line number Diff line number Diff line
diff --git a/src/exo/master/api.py b/src/exo/master/api.py
index 30f87e2a..4aac51fe 100644
--- a/src/exo/master/api.py
+++ b/src/exo/master/api.py
@@ -67,7 +67,14 @@ from exo.utils.channels import Receiver, Sender, channel
 from exo.utils.dashboard_path import find_dashboard
 from exo.utils.event_buffer import OrderedBuffer
 
-encoding = load_harmony_encoding(HarmonyEncodingName.HARMONY_GPT_OSS)
+_encoding: object = None
+
+
+def get_encoding():
+    global _encoding
+    if _encoding is None:
+        _encoding = load_harmony_encoding(HarmonyEncodingName.HARMONY_GPT_OSS)
+    return _encoding
 
 
 def chunk_to_response(
@@ -382,7 +389,7 @@ class API:
         )
 
     async def _process_gpt_oss(self, token_chunks: Receiver[TokenChunk]):
-        stream = StreamableParser(encoding, role=Role.ASSISTANT)
+        stream = StreamableParser(_encoding, role=Role.ASSISTANT)
         thinking = False
 
         async for chunk in token_chunks:
+167 −46
Original line number Diff line number Diff line
@@ -3,80 +3,201 @@
  stdenv,
  fetchFromGitHub,
  python3Packages,
  gitUpdater,
}:
python3Packages.buildPythonApplication rec {
  pname = "exo";
  version = "0.0.14-alpha";
  pyproject = true;
  replaceVars,
  macmon,

  # pyo3-bindings
  rustPlatform,

  # dashboard
  buildNpmPackage,
  fetchNpmDeps,

  writableTmpDirAsHomeHook,

  nix-update-script,
}:
let
  version = "1.0.63";
  src = fetchFromGitHub {
    name = "exo";
    owner = "exo-explore";
    repo = "exo";
    tag = "v${version}";
    hash = "sha256-GoYfpr6oFpreWQtSomOwgfzSoBAbjqGZ1mcc0u9TBl4=";
    hash = "sha256-aQ3rGLtT/zvIVdKQcwqODulzEHBKg7KMkBg3KJEscho=";
  };

  build-system = with python3Packages; [ setuptools ];
  pyo3-bindings = python3Packages.buildPythonPackage (finalAttrs: {
    pname = "exo-pyo3-bindings";
    inherit version src;
    pyproject = true;

  pythonRelaxDeps = true;
    buildAndTestSubdir = "rust/exo_pyo3_bindings";

    cargoDeps = rustPlatform.fetchCargoVendor {
      inherit (finalAttrs) pname src version;
      hash = "sha256-N7B1WFqPdqeNPZe9hXGyX7F3EbB1spzeKc19BFDDwls=";
    };

    # Bypass rust nightly features not being available on rust stable
    env.RUSTC_BOOTSTRAP = 1;

    nativeBuildInputs = [
      rustPlatform.cargoSetupHook
      rustPlatform.maturinBuildHook
    ];

    nativeCheckInputs = with python3Packages; [
      pytest-asyncio
      pytestCheckHook
    ];

    enabledTestPaths = [
      "rust/exo_pyo3_bindings/tests/"
    ];
  });

  dashboard = buildNpmPackage (finalAttrs: {
    pname = "exo-dashboard";
    inherit src version;

    sourceRoot = "${finalAttrs.src.name}/dashboard";

    npmDeps = fetchNpmDeps {
      inherit (finalAttrs)
        pname
        version
        src
        sourceRoot
        ;
      fetcherVersion = 2;
      hash = "sha256-w3FZL/yy8R+SWCQF7+v21sKyizvZMmipG6IfhJeSjyQ=";
    };
  });
in
python3Packages.buildPythonApplication (finalAttrs: {
  pname = "exo";
  pyproject = true;

  inherit version src;

  patches = [
    (replaceVars ./inject-dashboard-path.patch {
      dashboard = "${dashboard}/lib/node_modules/${dashboard.pname}/build";
    })
  ];

  pythonRemoveDeps = [ "uuid" ];
  postPatch = ''
    substituteInPlace pyproject.toml \
      --replace-fail "uv_build>=0.8.9,<0.9.0" "uv_build"
  ''
  # MemoryObjectStreamState was renamed in
  # https://github.com/agronholm/anyio/pull/1009/changes/bdc945a826d0d5917aea3517ceb9fe335b468094
  + ''
    substituteInPlace src/exo/utils/channels.py \
      --replace-fail \
        "MemoryObjectStreamState as AnyioState," \
        "_MemoryObjectStreamState as AnyioState,"
  ''
  + lib.optionalString stdenv.hostPlatform.isDarwin ''
    substituteInPlace src/exo/worker/utils/macmon.py \
      --replace-fail \
        'path = shutil.which("macmon")' \
        'path = "${lib.getExe macmon}"'

    substituteInPlace src/exo/worker/utils/tests/test_macmon.py \
      --replace-fail \
        'cmd=["macmon"' \
        'cmd=["${lib.getExe macmon}"'
  '';

  build-system = with python3Packages; [
    uv-build
  ];

  dependencies = with python3Packages; [
  pythonRelaxDeps = true;

  pythonRemoveDeps = [
    "types-aiofiles"
    "uuid"
  ];
  dependencies =
    with python3Packages;
    [
      aiofiles
      aiohttp
      aiohttp-cors
    aiofiles
      anyio
      fastapi
      filelock
      grpcio
      grpcio-tools
      httpx
      huggingface-hub
      hypercorn
      jinja2
    numpy
    nuitka
      loguru
      mlx
      mlx-lm
      nvidia-ml-py
      openai
      openai-harmony
      opencv-python
      pillow
      prometheus-client
    protobuf
      psutil
      pydantic
    requests
    rich
      pyo3-bindings
      rustworkx
      scapy
    tqdm
    transformers
      tiktoken
      tinygrad
      transformers
      uvloop
  ];
    ]
    ++ sqlalchemy.optional-dependencies.asyncio;

  pythonImportsCheck = [
    "exo"
    "exo.inference.tinygrad.models"
    "exo.main"
  ];

  nativeCheckInputs = with python3Packages; [
    mlx
    pytestCheckHook
  nativeCheckInputs = [
    python3Packages.pytest-asyncio
    python3Packages.pytestCheckHook
    writableTmpDirAsHomeHook
  ];

  disabledTestPaths = [
    "test/test_tokenizers.py"
  # Otherwise fails with 'import file mismatch'
  preCheck = ''
    rm src/exo/__init__.py
  '';

  disabledTests = lib.optionals stdenv.hostPlatform.isDarwin [
    # AssertionError: assert "MacMon not found in PATH" in str(exc_info.value)
    "test_macmon_not_found_raises_macmon_error"

    # ValueError: zip() argument 2 is longer than argument 1
    "test_events_processed_in_correct_order"
  ];

  # Tests require `mlx` which is not supported on linux.
  doCheck = stdenv.hostPlatform.isDarwin;
  disabledTestPaths = [
    # All tests hang indefinitely
    "src/exo/worker/tests/unittests/test_mlx/test_tokenizers.py"
  ];

  passthru = {
    updateScript = gitUpdater {
      rev-prefix = "v-";
    };
    updateScript = nix-update-script { };
    exo-pyo3-bindings = pyo3-bindings;
    exo-dashboard = dashboard;
  };

  meta = {
    description = "Run your own AI cluster at home with everyday devices";
    homepage = "https://github.com/exo-explore/exo";
    changelog = "https://github.com/exo-explore/exo/releases/tag/v${version}";
    changelog = "https://github.com/exo-explore/exo/releases/tag/${finalAttrs.src.tag}";
    license = lib.licenses.gpl3Only;
    maintainers = with lib.maintainers; [ GaetanLepage ];
    mainProgram = "exo";
  };
}
})