Loading pkgs/by-name/ex/exo/inject-dashboard-path.patch 0 → 100644 +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." pkgs/by-name/ex/exo/make-encoding-init-lazy.patch 0 → 100644 +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: pkgs/by-name/ex/exo/package.nix +167 −46 Original line number Diff line number Diff line Loading @@ -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"; }; } }) Loading
pkgs/by-name/ex/exo/inject-dashboard-path.patch 0 → 100644 +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."
pkgs/by-name/ex/exo/make-encoding-init-lazy.patch 0 → 100644 +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:
pkgs/by-name/ex/exo/package.nix +167 −46 Original line number Diff line number Diff line Loading @@ -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"; }; } })