Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 20 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,26 +190,37 @@ Build distributable artifacts:

```bash
npm run dist:desktop:mac-arm64
npm run dist:desktop:mac-x64
npm run dist:desktop:win-x64
```

Artifacts are written under `frontend/release/`. macOS ARM64 packaging has been
functionally validated. The Windows x64 build path is present but remains
experimental and should be validated on a Windows machine before release.
Artifacts are written under `frontend/release/`. Build macOS ARM64 on Apple
Silicon, macOS x64 on an Intel Mac, and Windows x64 on Windows so the packaged
PyInstaller backend has the same architecture as Electron and `llama-server`.
The packaging command validates the runtime and backend architectures before
creating the app. Windows x64 remains experimental and should be validated on a
Windows machine before release.

The public project does not ship Apple signing or notarization credentials.
Unsigned macOS builds may require users to approve the app in macOS privacy and
security settings.

## Local GGUF Models

The desktop package includes platform-specific `llama.cpp` runtime files. In
AurigaSQL Settings, the local demo model flow can download a supported GGUF model
into the local user-data directory and start `llama-server` on demand.
The repo contains platform-specific `llama.cpp` runtimes for macOS ARM64,
macOS Intel x64, and Windows x64. Web development mode selects the runtime for
the current machine; each desktop package includes only its target platform's
files. Users do not need to install Ollama or `llama.cpp` for the local Demo
flow. These runtimes are tracked in the repository rather than installed by
`npm ci`.

For development, runtime locations and the local model port can be overridden
with the `AURIGASQL_LLAMA_SERVER_PATH` and
`AURIGASQL_LOCAL_MODEL_PORT` variables shown in `.env.example`.
In AurigaSQL Settings, the local Demo flow downloads the Qwen3 1.7B Q4_K_M GGUF
model into the local user-data directory and starts `llama-server` on demand.
The large GGUF model is intentionally not stored in this repository.

Advanced development setups can override the selected executable and local
model port with `AURIGASQL_LLAMA_SERVER_PATH` and
`AURIGASQL_LOCAL_MODEL_PORT`, as shown in `.env.example`.

## License

Expand Down
16 changes: 12 additions & 4 deletions backend/api/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
)
from shared.config import CONFIG_DIR, RESOURCE_ROOT, RUNTIME_ROOT, settings
from shared.llm import call_llm
from shared.llama_runtime import platform_runtime_relative_path
from shared.llm_profile_store import (
MASK_SENTINELS,
create_profile,
Expand Down Expand Up @@ -164,16 +165,23 @@ def _local_model_path() -> Path:

def _find_llama_server_path() -> Path:
env_path = os.getenv("AURIGASQL_LLAMA_SERVER_PATH", "").strip()
env_candidate = Path(env_path).expanduser() if env_path else None
if env_candidate and env_candidate.exists():
return env_candidate

relative_runtime = platform_runtime_relative_path()
executable_name = relative_runtime.name
candidates = [
Path(env_path).expanduser() if env_path else None,
RESOURCE_ROOT / "llama.cpp" / "llama-server",
Path(__file__).resolve().parents[2] / "frontend" / "vendor" / "llama.cpp" / "macos" / "llama-server",
env_candidate,
RESOURCE_ROOT / "llama.cpp" / executable_name,
Path(__file__).resolve().parents[2] / "frontend" / "vendor" / "llama.cpp" / relative_runtime,
]
for candidate in candidates:
if candidate and candidate.exists():
return candidate
attempted = ", ".join(str(candidate) for candidate in candidates if candidate)
raise FileNotFoundError(
"llama-server was not found. Expected it in app resources at llama.cpp/llama-server."
f"llama-server was not found for {relative_runtime.parent}. Tried: {attempted}"
)


Expand Down
7 changes: 7 additions & 0 deletions backend/packaging/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,16 @@ Release builds remain separate:

```bash
npm run dist:desktop:mac-arm64
npm run dist:desktop:mac-x64
npm run dist:desktop:win-x64
```

Run each command on its matching operating system and CPU architecture. Before
electron-builder runs, `frontend/scripts/prepare-llama-runtime.cjs` validates
the selected llama.cpp runtime and packaged backend, then copies only that
platform's runtime into the Git-ignored `frontend/.llama-runtime/` staging
directory.

Use the packaged backend smoke directly when debugging resource paths:

```bash
Expand Down
33 changes: 33 additions & 0 deletions backend/shared/llama_runtime.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
"""Resolve the bundled llama.cpp runtime for supported desktop platforms."""

from __future__ import annotations

import platform
from pathlib import Path


SUPPORTED_LLAMA_PLATFORMS = "macOS ARM64, macOS x64, and Windows x64"


def platform_runtime_relative_path(
system: str | None = None,
machine: str | None = None,
) -> Path:
"""Return the repo-relative runtime executable for the requested platform."""

system_name = (system or platform.system()).strip().lower()
machine_name = (machine or platform.machine()).strip().lower()

if system_name == "darwin":
if machine_name in {"arm64", "aarch64"}:
return Path("macos-arm64") / "llama-server"
if machine_name in {"x86_64", "amd64"}:
return Path("macos-x64") / "llama-server"
elif system_name == "windows" and machine_name in {"x86_64", "amd64"}:
return Path("windows-x64") / "llama-server.exe"

raise RuntimeError(
f"Unsupported llama.cpp platform: system={system or platform.system()!r}, "
f"machine={machine or platform.machine()!r}. Supported platforms: "
f"{SUPPORTED_LLAMA_PLATFORMS}."
)
32 changes: 32 additions & 0 deletions backend/tests/test_llama_runtime.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from pathlib import Path
import unittest

from shared.llama_runtime import platform_runtime_relative_path


class PlatformRuntimeRelativePathTests(unittest.TestCase):
def test_macos_arm64(self) -> None:
self.assertEqual(
platform_runtime_relative_path("Darwin", "arm64"),
Path("macos-arm64/llama-server"),
)

def test_macos_x64(self) -> None:
self.assertEqual(
platform_runtime_relative_path("Darwin", "x86_64"),
Path("macos-x64/llama-server"),
)

def test_windows_x64(self) -> None:
self.assertEqual(
platform_runtime_relative_path("Windows", "AMD64"),
Path("windows-x64/llama-server.exe"),
)

def test_unsupported_platform_reports_detected_values(self) -> None:
with self.assertRaisesRegex(RuntimeError, "Linux.*riscv64"):
platform_runtime_relative_path("Linux", "riscv64")


if __name__ == "__main__":
unittest.main()
1 change: 1 addition & 0 deletions frontend/.gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
node_modules
dist
release
.llama-runtime
.desktop/
plan/
.env
Expand Down
17 changes: 11 additions & 6 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,21 @@
"build": "vite build",
"dev:desktop": "concurrently -k -n vite,electron -c cyan,magenta \"npm run dev -- --host 127.0.0.1\" \"wait-on http://127.0.0.1:5173 && electron .\"",
"pack:desktop": "npm run pack:desktop:mac-arm64",
"pack:desktop:mac-arm64": "npm run build:backend:mac && npm run build && CSC_IDENTITY_AUTO_DISCOVERY=false electron-builder --dir --mac --arm64 -c.mac.notarize=false",
"pack:desktop:win-x64": "npm run build:backend:win && npm run build && electron-builder --dir --win --x64",
"pack:desktop:mac-arm64": "npm run build:backend:mac && npm run prepare:llama:mac-arm64 && npm run build && CSC_IDENTITY_AUTO_DISCOVERY=false electron-builder --dir --mac --arm64 -c.mac.notarize=false",
"pack:desktop:mac-x64": "npm run build:backend:mac && npm run prepare:llama:mac-x64 && npm run build && CSC_IDENTITY_AUTO_DISCOVERY=false electron-builder --dir --mac --x64 -c.mac.notarize=false",
"pack:desktop:win-x64": "npm run build:backend:win && npm run prepare:llama:win-x64 && npm run build && electron-builder --dir --win --x64",
"dist:desktop": "npm run dist:desktop:mac-arm64",
"preview": "vite preview",
"test": "vitest run",
"typecheck": "tsc --noEmit",
"build:backend:mac": "bash ../backend/packaging/build-macos.sh",
"build:backend:win": "powershell -ExecutionPolicy Bypass -File ../backend/packaging/build-windows.ps1",
"dist:desktop:mac-arm64": "npm run build:backend:mac && npm run build && electron-builder --mac --arm64",
"dist:desktop:win-x64": "npm run build:backend:win && npm run build && electron-builder --win --x64"
"prepare:llama:mac-arm64": "node scripts/prepare-llama-runtime.cjs macos-arm64 electron-backend/aurigasql-bff",
"prepare:llama:mac-x64": "node scripts/prepare-llama-runtime.cjs macos-x64 electron-backend/aurigasql-bff",
"prepare:llama:win-x64": "node scripts/prepare-llama-runtime.cjs windows-x64 electron-backend/aurigasql-bff.exe",
"dist:desktop:mac-arm64": "npm run build:backend:mac && npm run prepare:llama:mac-arm64 && npm run build && electron-builder --mac --arm64",
"dist:desktop:mac-x64": "npm run build:backend:mac && npm run prepare:llama:mac-x64 && npm run build && electron-builder --mac --x64",
"dist:desktop:win-x64": "npm run build:backend:win && npm run prepare:llama:win-x64 && npm run build && electron-builder --win --x64"
},
"dependencies": {
"@lobehub/icons": "^5.10.0",
Expand Down Expand Up @@ -94,7 +99,7 @@
],
"extraResources": [
{
"from": "vendor/llama.cpp/macos",
"from": ".llama-runtime",
"to": "llama.cpp",
"filter": [
"LICENSE",
Expand All @@ -115,7 +120,7 @@
"win": {
"extraResources": [
{
"from": "vendor/llama.cpp/windows-x64",
"from": ".llama-runtime",
"to": "llama.cpp",
"filter": [
"LICENSE",
Expand Down
90 changes: 90 additions & 0 deletions frontend/scripts/prepare-llama-runtime.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
const fs = require("node:fs");
const path = require("node:path");

const TARGETS = {
"macos-arm64": {
executable: "llama-server",
libraryExtension: ".dylib",
format: "macho",
machine: 0x0100000c,
machineLabel: "arm64",
},
"macos-x64": {
executable: "llama-server",
libraryExtension: ".dylib",
format: "macho",
machine: 0x01000007,
machineLabel: "x86_64",
},
"windows-x64": {
executable: "llama-server.exe",
libraryExtension: ".dll",
format: "pe",
machine: 0x8664,
machineLabel: "x86_64",
},
};

function fail(message) {
throw new Error(`llama.cpp runtime validation failed: ${message}`);
}

function binaryMachine(filePath, format) {
const buffer = fs.readFileSync(filePath);
if (format === "macho") {
if (buffer.length < 8 || buffer.readUInt32LE(0) !== 0xfeedfacf) {
fail(`${filePath} is not a 64-bit little-endian Mach-O binary`);
}
return buffer.readUInt32LE(4);
}

if (buffer.length < 64 || buffer.toString("ascii", 0, 2) !== "MZ") {
fail(`${filePath} is not a PE binary`);
}
const peOffset = buffer.readUInt32LE(0x3c);
if (buffer.toString("ascii", peOffset, peOffset + 4) !== "PE\0\0") {
fail(`${filePath} has an invalid PE header`);
}
return buffer.readUInt16LE(peOffset + 4);
}

function validateBinary(filePath, target) {
if (!fs.existsSync(filePath)) fail(`missing ${filePath}`);
const actual = binaryMachine(filePath, target.format);
if (actual !== target.machine) {
fail(`${filePath} is not ${target.machineLabel} (machine 0x${actual.toString(16)})`);
}
}

function main() {
const targetName = process.argv[2];
const target = TARGETS[targetName];
if (!target) {
fail(`unknown target ${JSON.stringify(targetName)}; expected ${Object.keys(TARGETS).join(", ")}`);
}

const frontendDir = path.resolve(__dirname, "..");
const sourceDir = path.join(frontendDir, "vendor", "llama.cpp", targetName);
const stagingDir = path.join(frontendDir, ".llama-runtime");
if (!fs.existsSync(sourceDir)) fail(`missing runtime directory ${sourceDir}`);

const executable = path.join(sourceDir, target.executable);
validateBinary(executable, target);
const libraries = fs.readdirSync(sourceDir).filter((name) => name.endsWith(target.libraryExtension));
if (libraries.length === 0) fail(`no ${target.libraryExtension} libraries found in ${sourceDir}`);
for (const library of libraries) validateBinary(path.join(sourceDir, library), target);

if (target.format === "macho") {
const mode = fs.statSync(executable).mode;
if ((mode & 0o111) === 0) fail(`${executable} is not executable`);
}

const backendPath = process.argv[3];
if (backendPath) validateBinary(path.resolve(frontendDir, backendPath), target);

fs.rmSync(stagingDir, { recursive: true, force: true });
fs.cpSync(sourceDir, stagingDir, { recursive: true, dereference: false });
process.stdout.write(`Prepared llama.cpp ${targetName} runtime at ${stagingDir}\n`);
}

main();
18 changes: 18 additions & 0 deletions frontend/vendor/llama.cpp/macos-arm64/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
This directory contains the macOS ARM64 llama.cpp runtime bundled with the
AurigaSQL desktop app.

- Version: b9990 (`259ae1df8`)
- Architecture: arm64
- Source archive: https://github.com/ggml-org/llama.cpp/releases/download/b9990/llama-b9990-bin-macos-arm64.tar.gz
- Source archive SHA-256: `924d9397144b66524983ecefc174d659c248f8c4297ee252ab40ccea625c4077`
- Executable SHA-256: `af7f9fbdfc9b2187188b646e8b51db121bb90e574c08e510ce4ad0b4ac21c648`
- Verified: 2026-07-22
- License: MIT; see `LICENSE`

Expected packaged path:

```text
resources/llama.cpp/llama-server
```

The backend starts this binary when the user chooses the local demo model.
21 changes: 21 additions & 0 deletions frontend/vendor/llama.cpp/macos-x64/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2023-2026 The ggml authors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
19 changes: 19 additions & 0 deletions frontend/vendor/llama.cpp/macos-x64/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# llama.cpp macOS x64 Runtime

This directory contains the macOS Intel runtime bundled with AurigaSQL.

- Version: b9990 (`259ae1df8`)
- Architecture: x86_64
- Source archive: https://github.com/ggml-org/llama.cpp/releases/download/b9990/llama-b9990-bin-macos-x64.tar.gz
- Source archive SHA-256: `3e5cb5767c84a49cfa53f762334ea7ae4302856d06d2ad6edb8f4d855803be64`
- Verified: 2026-07-22
- License: MIT; see `LICENSE`

Expected packaged path:

```text
resources/llama.cpp/llama-server
```

Only `llama-server` and its required dynamic libraries are bundled into the
AurigaSQL app.
Binary file not shown.
1 change: 1 addition & 0 deletions frontend/vendor/llama.cpp/macos-x64/libggml-base.0.dylib
1 change: 1 addition & 0 deletions frontend/vendor/llama.cpp/macos-x64/libggml-base.dylib
Binary file not shown.
1 change: 1 addition & 0 deletions frontend/vendor/llama.cpp/macos-x64/libggml-blas.0.dylib
1 change: 1 addition & 0 deletions frontend/vendor/llama.cpp/macos-x64/libggml-blas.dylib
Binary file not shown.
1 change: 1 addition & 0 deletions frontend/vendor/llama.cpp/macos-x64/libggml-cpu.0.dylib
1 change: 1 addition & 0 deletions frontend/vendor/llama.cpp/macos-x64/libggml-cpu.dylib
Binary file not shown.
1 change: 1 addition & 0 deletions frontend/vendor/llama.cpp/macos-x64/libggml-rpc.0.dylib
1 change: 1 addition & 0 deletions frontend/vendor/llama.cpp/macos-x64/libggml-rpc.dylib
Binary file not shown.
1 change: 1 addition & 0 deletions frontend/vendor/llama.cpp/macos-x64/libggml.0.dylib
Loading