ethicallama 0.1.0__tar.gz
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.
- ethicallama-0.1.0/AGENTS.md +346 -0
- ethicallama-0.1.0/CHANGELOG.md +104 -0
- ethicallama-0.1.0/CREDITS.md +16 -0
- ethicallama-0.1.0/LICENSE +21 -0
- ethicallama-0.1.0/PKG-INFO +397 -0
- ethicallama-0.1.0/README.md +351 -0
- ethicallama-0.1.0/ethllama-core/Cargo.lock +359 -0
- ethicallama-0.1.0/ethllama-core/Cargo.toml +19 -0
- ethicallama-0.1.0/ethllama-core/build.rs +61 -0
- ethicallama-0.1.0/ethllama-core/src/lib.rs +160 -0
- ethicallama-0.1.0/ethllama-core/src/llama.rs +890 -0
- ethicallama-0.1.0/ethllama-core/src/shim.cpp +100 -0
- ethicallama-0.1.0/ethllama-core/src/utils.rs +280 -0
- ethicallama-0.1.0/pyproject.toml +82 -0
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
# AGENTS.md — ethicallama Project Memory
|
|
2
|
+
|
|
3
|
+
> This file captures architecture, patterns, decisions, and constraints discovered during development.
|
|
4
|
+
> Update this file whenever you learn something important that future coding agents should know.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Project Overview
|
|
9
|
+
|
|
10
|
+
**ethicallama** — ethical, local-only inference wrapper for llama.cpp and other engines.
|
|
11
|
+
|
|
12
|
+
- **Rust core** (`ethllama-core/`): PyO3 bindings to llama.cpp FFI
|
|
13
|
+
- **Python CLI/API** (`ethllama/`): Click CLI + optional FastAPI (OpenAI-compatible)
|
|
14
|
+
- **Linux-first, no Windows, no telemetry by default**
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Directory Layout
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
ethicallama/
|
|
22
|
+
├── ethllama-core/ # Rust crate (cdylib, PyO3)
|
|
23
|
+
│ ├── Cargo.toml # Dependencies: pyo3, serde, libloading, anyhow, cmake (build-dep)
|
|
24
|
+
│ ├── build.rs # Compiles llama.cpp via cmake crate (requires submodule)
|
|
25
|
+
│ └── src/
|
|
26
|
+
│ ├── lib.rs # PyO3 #[pymodule]: exports PyLlamaModel class
|
|
27
|
+
│ ├── llama.rs # FFI declarations (extern "C") matching real llama.h API
|
|
28
|
+
│ └── utils.rs # GPU detection (nvidia-smi, rocm-smi, vulkaninfo)
|
|
29
|
+
│
|
|
30
|
+
├── pyproject.toml # maturin build config + Python deps (repo root)
|
|
31
|
+
├── ethllama/ # Python package
|
|
32
|
+
│ ├── __init__.py # Re-exports from submodules
|
|
33
|
+
│ ├── cli.py # Click CLI (11 subcommands: run, pull, list, index, config, serve, engines, quantize, rm, info, transcribe)
|
|
34
|
+
│ ├── cli_mgmt.py # Model management subcommands (rm, info)
|
|
35
|
+
│ ├── cli_stt.py # Speech-to-text subcommand (transcribe)
|
|
36
|
+
│ ├── api.py # FastAPI (OpenAI-compatible, opt-in)
|
|
37
|
+
│ ├── config.py # Config load/save/init (~/.ethllama/config.yaml)
|
|
38
|
+
│ ├── engines.py # EngineConfig with Jinja2 templating for custom engine binaries
|
|
39
|
+
│ ├── index.py # Model index (~/.ethllama/index.json), path resolution
|
|
40
|
+
│ ├── pull.py # Model pulling from HuggingFace Hub (optional)
|
|
41
|
+
│ ├── convert.py # Opt-in Safetensors → GGUF conversion
|
|
42
|
+
│ └── tests/
|
|
43
|
+
│ └── test_cli.py # 14 CLI tests (pytest)
|
|
44
|
+
│
|
|
45
|
+
├── docs/
|
|
46
|
+
│ ├── CREDITS.md # Dependency credits (llama.cpp, PyO3, FastAPI, whisper.cpp)
|
|
47
|
+
│ ├── PRIVACY.md # No telemetry policy
|
|
48
|
+
│ ├── USAGE.md # Full CLI/API/config documentation
|
|
49
|
+
│ └── examples/ # Example engine YAML configs
|
|
50
|
+
│ ├── llama-cpp.yaml
|
|
51
|
+
│ ├── whisper-cpp.yaml
|
|
52
|
+
│ ├── custom-engine.yaml
|
|
53
|
+
│ └── README.md
|
|
54
|
+
│
|
|
55
|
+
├── scripts/
|
|
56
|
+
│ ├── setup.sh # Prerequisites + build + install
|
|
57
|
+
│ └── benchmark.sh # Timed inference benchmarking
|
|
58
|
+
│
|
|
59
|
+
├── flake.nix # Nix development shell
|
|
60
|
+
├── README.md # Project documentation
|
|
61
|
+
└── AGENTS.md # This file
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Architecture & Data Flow
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
User CLI (click) FastAPI (uvicorn)
|
|
70
|
+
| |
|
|
71
|
+
v v
|
|
72
|
+
ethllama Python package
|
|
73
|
+
| |
|
|
74
|
+
v v
|
|
75
|
+
EngineConfig (Jinja2) OR PyLlamaModel (Rust/PyO3)
|
|
76
|
+
| |
|
|
77
|
+
v v
|
|
78
|
+
Custom binary (e.g., llama-cli) llama.cpp C library
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Two Inference Paths
|
|
82
|
+
|
|
83
|
+
1. **Native Rust path**: `PyLlamaModel` class via PyO3 → calls llama.cpp FFI directly
|
|
84
|
+
2. **Engine binary path**: `EngineConfig.render_command()` → Jinja2 template → shell command to external binary
|
|
85
|
+
|
|
86
|
+
The `run` CLI command tries native first, falls back to engine binary if the model isn't loadable via Rust.
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Key Patterns & Conventions
|
|
91
|
+
|
|
92
|
+
### Rust Core (`ethllama-core/src/`)
|
|
93
|
+
|
|
94
|
+
- **FFI declarations go in `llama.rs`** — all `extern "C"` blocks are consolidated here, NOT in `lib.rs`
|
|
95
|
+
- **`llama.rs`** defines: `LlamaModel` (opaque, `#[repr(C)]` with `_private: [u8; 0]`), `LlamaModelParams` (with `Default` impl), and all unsafe FFI wrappers
|
|
96
|
+
- **`lib.rs`** only does: `mod llama; mod utils;`, PyO3 `#[pymodule]`, and `#[pyclass]` wrappers
|
|
97
|
+
- **`utils.rs`** is for system introspection: GPU detection, file system queries, etc.
|
|
98
|
+
- **Memory safety**: `PyLlamaModel` has a `Drop` impl that calls `llama_free`, and `unsafe impl Send` for PyO3 thread safety
|
|
99
|
+
- **Build**: `cmake` crate is a **build-dependency** (in `[build-dependencies]` in Cargo.toml). The `build.rs` uses the `cmake` crate to build the full llama.cpp library tree, and panics with a clear message if `llama.cpp/` submodule is missing — it does NOT auto-clone during build. Additional build-deps: `cc` for compiling any C shim sources if needed.
|
|
100
|
+
|
|
101
|
+
### Rust Core (`ethllama-core/src/`) — Current State
|
|
102
|
+
|
|
103
|
+
- **`build.rs`** uses the `cmake` crate to build llama.cpp as a static library (replaced the old `cc`-based approach that only compiled a subset of source files)
|
|
104
|
+
- **`llama.rs`** contains complete FFI bindings matching the real `llama.h` API:
|
|
105
|
+
- 4 opaque types (`llama_model`, `llama_context`, `llama_vocab`, `llama_sampler`)
|
|
106
|
+
- 6 struct types with exact `#[repr(C)]` layouts: `llama_model_params`, `llama_context_params` (~35 fields), `llama_batch`, `llama_sampler_chain_params`, `llama_token_data`, `llama_token_data_array`
|
|
107
|
+
- 30+ `extern "C"` function declarations covering model loading, context creation, tokenization, decoding, and the backend sampling API
|
|
108
|
+
- Safe helper functions: `load_model()`, `tokenize()`, `detokenize()`, `infer_tokens()`
|
|
109
|
+
- **`lib.rs`** `PyLlamaModel` implements real inference:
|
|
110
|
+
- Constructor: calls `llama_backend_init()`, loads model via `llama_model_load_from_file()`, creates context via `llama_init_from_model()`
|
|
111
|
+
- `infer()` method: tokenizes prompt, runs `llama_decode()` for prefill, builds a sampler chain (greedy or temp+top_p+top_k+dist), loops token-by-token with `llama_sampler_sample()` and `llama_decode()`, detokenizes output
|
|
112
|
+
- `Drop`: frees context, model, and calls `llama_backend_free()`
|
|
113
|
+
- **Linking**: 4 static libraries — `libllama.a`, `libggml.a`, `libggml-cpu.a`, `libggml-base.a` — plus pthread, dl, stdc++
|
|
114
|
+
- **`llama_backend_init/llama_backend_free`** are called per-instance (not global); fine for typical single-model usage
|
|
115
|
+
|
|
116
|
+
### Known Rust Core Limitations
|
|
117
|
+
- `llama_backend_free()` is called once per `PyLlamaModel::drop()`. If multiple models are created in the same Python process, the backend will be freed after the first model is destroyed. For multi-model workflows, a global reference-counted backend init/free should be implemented.
|
|
118
|
+
- The `llama_context_params` struct alignment depends on repr(C) matching the C compiler's layout. Verified on x86_64 Linux with GCC 16.
|
|
119
|
+
|
|
120
|
+
### Python Package (`ethllama/`)
|
|
121
|
+
|
|
122
|
+
- **CLI**: click-based, single `@click.group()` entry point in `cli.py`, 8 subcommands (`run`, `pull`, `list`, `index`, `config`, `serve`, `engines`, `quantize`)
|
|
123
|
+
- **Config**: YAML at `~/.ethllama/config.yaml`, loaded via `config.load_config()`, defaults in `DEFAULT_CONFIG` dict
|
|
124
|
+
- **Engine configs**: YAML at `~/.ethllama/engines/*.yaml`, parsed by `EngineConfig` class with Jinja2 templating
|
|
125
|
+
- **Model index**: JSON at `~/.ethllama/index.json`, manages symlinks/hardlinks for storage efficiency
|
|
126
|
+
- **API**: FastAPI is **opt-in only** (extra dependency group `ethllama[api]`). Endpoints: `/v1/chat/completions`, `/v1/completions`, `/v1/models`, `/v1/embeddings`
|
|
127
|
+
- **Pulling**: HuggingFace Hub (`ethllama[pull]`) and Ollama registry (built-in, `requests`-based, no auth needed for public models). Ollama's `application/vnd.ollama.image.model` blob **IS a complete GGUF file** — no conversion needed.
|
|
128
|
+
- **Conversion**: torch+transformers is optional (`ethllama[convert]`)
|
|
129
|
+
- **Quantize**: `ethllama quantize <model>` command built-in (uses llama.cpp's `llama-quantize` binary, 11 quantization types supported, default q4_k_m)
|
|
130
|
+
|
|
131
|
+
### Jinja2 Template Variables (for engine configs)
|
|
132
|
+
|
|
133
|
+
Available variables in `args_template`:
|
|
134
|
+
- `{{ binary }}` — engine binary path
|
|
135
|
+
- `{{ model_path }}` — model file path
|
|
136
|
+
- `{{ prompt }}` — input prompt
|
|
137
|
+
- `{{ temperature }}`, `{{ top_p }}`, `{{ top_k }}` — sampling params
|
|
138
|
+
- `{{ threads }}` — CPU threads
|
|
139
|
+
- `{{ n_gpu_layers }}` — GPU offload layers
|
|
140
|
+
- `{{ gpu_backend }}` — selected GPU backend
|
|
141
|
+
- `{{ output }}` — output file path
|
|
142
|
+
|
|
143
|
+
### Engine Config YAML Schema
|
|
144
|
+
|
|
145
|
+
```yaml
|
|
146
|
+
name: engine-name # Unique identifier
|
|
147
|
+
type: text|stt|tts|image # Engine type
|
|
148
|
+
binary: /path/to/binary # Executable path
|
|
149
|
+
args_template: "..." # Jinja2 template for CLI args
|
|
150
|
+
env: # Environment variables (optional)
|
|
151
|
+
KEY: value
|
|
152
|
+
pre_check: "..." # Shell command to verify engine (optional)
|
|
153
|
+
supports_streaming: true|false # Streaming support flag (optional)
|
|
154
|
+
model_extensions: # Supported file extensions (optional)
|
|
155
|
+
- .gguf
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Constraints & Decisions
|
|
161
|
+
|
|
162
|
+
### Inviolable Rules
|
|
163
|
+
|
|
164
|
+
1. **No Windows support** — reject any Windows-specific code
|
|
165
|
+
2. **No telemetry by default** — telemetry requires explicit `telemetry.enabled: true` in config. The `config.py` init flow warns users before enabling.
|
|
166
|
+
3. **No model duplication** — use symlinks/hardlinks for storage efficiency via model index
|
|
167
|
+
4. **GPU backend choice** — user-selected (Vulkan/ROCm/CUDA/CPU), auto-detected as priority fallback
|
|
168
|
+
5. **LLM inference is local-only** — no cloud inference calls, no API calls to external model providers
|
|
169
|
+
|
|
170
|
+
### Build Dependencies
|
|
171
|
+
|
|
172
|
+
- `llama.cpp` is a **git submodule** at `ethllama-core/llama.cpp/`
|
|
173
|
+
- Must run `git submodule update --init --recursive` before building
|
|
174
|
+
- Build script (`build.rs`) uses `cmake` crate to build the full llama.cpp library tree
|
|
175
|
+
- Use `cargo build --release -p ethllama-core` for the Rust crate
|
|
176
|
+
- Use `maturin develop` or `pip install -e .` for the Python package
|
|
177
|
+
|
|
178
|
+
### Development Setup with `uv`
|
|
179
|
+
|
|
180
|
+
`uv` is the recommended Python runtime/venv manager for this project. It works seamlessly with PyO3/maturin:
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
# Create a virtual environment
|
|
184
|
+
uv venv
|
|
185
|
+
|
|
186
|
+
# Activate it (or use `uv run` for one-off commands)
|
|
187
|
+
source .venv/bin/activate
|
|
188
|
+
|
|
189
|
+
# Install maturin + all deps
|
|
190
|
+
uv pip install maturin ".[all]"
|
|
191
|
+
|
|
192
|
+
# Build the Rust crate and install Python package in one step
|
|
193
|
+
maturin develop
|
|
194
|
+
|
|
195
|
+
# Or equivalently, for production-style wheel:
|
|
196
|
+
uv pip install -e ".[all]"
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
**Why uv works with PyO3**: `maturin develop` discovers the active Python interpreter from the venv. `uv`'s venvs are standard virtual environments — maturin sees them the same as any other venv. No special configuration needed.
|
|
200
|
+
|
|
201
|
+
Key commands during development:
|
|
202
|
+
- `uv run ethllama --help` — run CLI without activating venv
|
|
203
|
+
- `uv run pytest ethllama/tests/ -v` — run tests
|
|
204
|
+
- `uv pip install -e ".[all]"` — reinstall after Python-only changes
|
|
205
|
+
- `maturin develop --release` — rebuild Rust core
|
|
206
|
+
|
|
207
|
+
### Ollama Registry Protocol
|
|
208
|
+
|
|
209
|
+
When implementing or modifying `pull_from_ollama()`:
|
|
210
|
+
- **The model blob IS a GGUF file** — `application/vnd.ollama.image.model` contains the raw GGUF bytes, no conversion needed. Verify with magic bytes `b"GGUF"` (0x46554747 LE) on download.
|
|
211
|
+
- **OCI Distribution Spec v2** — uses `/v2/<namespace>/<repo>/manifests/<tag>` for manifest and `/v2/<namespace>/<repo>/blobs/sha256:<digest>` for blobs.
|
|
212
|
+
- **No auth needed** for public models on `registry.ollama.ai`.
|
|
213
|
+
- **Accept header required** — must set `Accept: application/vnd.docker.distribution.manifest.v2+json` on manifest GET.
|
|
214
|
+
- **Hostname detection** in `_parse_model_ref`: dots in the first path component distinguish hostnames (e.g., `registry.ollama.ai/library/foo`) from namespaces (`foo/bar`).
|
|
215
|
+
- **Content-Type bug**: manifest returns `Content-Type: text/plain; charset=utf-8` (known Ollama issue), parse body as JSON regardless.
|
|
216
|
+
- **307 redirect**: blob GETs redirect to Cloudflare R2 (`*.r2.cloudflarestorage.com`). Standard `requests` follows it automatically.
|
|
217
|
+
- **Resumable downloads**: use `.partial` temp files with `Range` headers for resume. Verify SHA-256 after completion.
|
|
218
|
+
- Existing reference implementations: `iven86/ollama_gguf_downloader`, `olamide226/ollama-gguf-downloader`, `leeroopedia/workflow-ollama-ollama-model-registry-operations`.
|
|
219
|
+
|
|
220
|
+
### Quantize Command
|
|
221
|
+
|
|
222
|
+
The `ethllama quantize <model>` command:
|
|
223
|
+
- Accepts `--type` (11 quantization types, default `q4_k_m`) and `--binary` (auto-detected from llama.cpp build dirs or PATH via `shutil.which()`)
|
|
224
|
+
- Resolves model from index, auto-generates output path (`<model>-<type>.gguf`)
|
|
225
|
+
- Runs `llama-quantize` via subprocess with progress logging
|
|
226
|
+
|
|
227
|
+
### Embeddings Endpoint
|
|
228
|
+
|
|
229
|
+
The `/v1/embeddings` endpoint in `api.py`:
|
|
230
|
+
- Accepts `EmbeddingRequest` model with `input` (str or list) and `model` fields
|
|
231
|
+
- Returns deterministic pseudo-embeddings (fixed 768-dim vector) for now. When the Rust core is wired to the API, replace with real embeddings from llama.cpp.
|
|
232
|
+
|
|
233
|
+
### Python Dependencies
|
|
234
|
+
|
|
235
|
+
- **Required**: click, pyyaml, jinja2, tqdm, requests
|
|
236
|
+
- **Optional (api)**: fastapi, uvicorn, pydantic
|
|
237
|
+
- **Optional (pull)**: huggingface_hub
|
|
238
|
+
- **Optional (convert)**: torch, transformers
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## Testing
|
|
243
|
+
|
|
244
|
+
- Python tests: `pytest ethllama/tests/ -v` (14 CLI tests, covering basic CLI, pull, quantize, ollama pull)
|
|
245
|
+
- Rust tests: None yet (no test harness for FFI crate)
|
|
246
|
+
- Test the CLI via `click.testing.CliRunner` (already in test_cli.py)
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## Project Skills
|
|
251
|
+
|
|
252
|
+
**Before every non-trivial implementation task, check `.agents/skills/` for a matching skill and load it with the `skill` tool.** Skills contain the exact workflow, code patterns, and reference files for recurring operations — loading them saves time and prevents mistakes.
|
|
253
|
+
|
|
254
|
+
| Skill | Load when... |
|
|
255
|
+
|-------|-------------|
|
|
256
|
+
| `rust-ffi-bind` | Adding new llama.cpp C API functions through Rust FFI → PyO3 (three-layer pattern: extern "C" → safe wrapper → pyclass) |
|
|
257
|
+
| `ollama-registry-pull` | Working with Ollama's OCI registry (pull, protocol quirks, SHA-256 verification, Content-Type bug, 307 redirects) |
|
|
258
|
+
|
|
259
|
+
If you encounter a new recurring workflow during development, write it as a skill in `.agents/skills/<name>/SKILL.md` so future agent sessions can reuse the pattern.
|
|
260
|
+
|
|
261
|
+
**Skills are living documents.** When executing a skill's workflow (or any undocumented workflow that should have had a matching skill), if you discover a new fact, edge case, gotcha, or improvement — update the `SKILL.md` to capture it. Skills degrade fast if they omit critical quirks; the first execution always finds something the skill author missed. If you found yourself doing a structured multi-step workflow that has no skill yet, write one. Future agents (and you) will benefit more from a rough-but-honest skill than from none.
|
|
262
|
+
|
|
263
|
+
## Nix Development
|
|
264
|
+
|
|
265
|
+
The project ships a `flake.nix` that provides a reproducible dev shell with
|
|
266
|
+
the full Rust + Python + llama.cpp build chain pre-installed. Use it if you
|
|
267
|
+
are on NixOS or have the Nix package manager installed.
|
|
268
|
+
|
|
269
|
+
### What the dev shell provides
|
|
270
|
+
|
|
271
|
+
- **Rust toolchain** (latest stable via `rust-overlay`) - `cargo`, `rustc`,
|
|
272
|
+
`clippy`, `rustfmt`, `rust-analyzer`
|
|
273
|
+
- **Python 3** + `maturin` + `pip` on `PATH` (so `pip install -e .` also works
|
|
274
|
+
without a separate venv install)
|
|
275
|
+
- **Native build deps** - `cmake`, `ninja`, `pkg-config`, `openssl`, `git`
|
|
276
|
+
- **C/C++ compilers** - `gcc` and `clang` (the `cc` and `cmake` crates pick
|
|
277
|
+
whichever is first on `PATH`)
|
|
278
|
+
- **Optional GPU** - `vulkan-headers`, `vulkan-loader` (only used when
|
|
279
|
+
building the standalone `llama.cpp` binaries with `-DLLAMA_VULKAN=ON`; the
|
|
280
|
+
bundled `ethllama-core` is CPU-only)
|
|
281
|
+
- **`PKG_CONFIG_PATH`** set so pkg-config consumers can find `openssl`
|
|
282
|
+
|
|
283
|
+
### Entering the shell
|
|
284
|
+
|
|
285
|
+
```bash
|
|
286
|
+
nix develop # default shell with everything
|
|
287
|
+
# or
|
|
288
|
+
nix develop .#default # same thing, explicit
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### shellHook behavior
|
|
292
|
+
|
|
293
|
+
- If `.gitmodules` exists but the `ethllama-core/llama.cpp/common` directory
|
|
294
|
+
is missing, runs `git submodule update --init --recursive` automatically.
|
|
295
|
+
- Prints a banner with versions of all key tools.
|
|
296
|
+
- Prints a quickstart reminder (uv workflow + standalone llama.cpp build).
|
|
297
|
+
|
|
298
|
+
### Quickstart (from inside the dev shell)
|
|
299
|
+
|
|
300
|
+
```bash
|
|
301
|
+
uv venv
|
|
302
|
+
source .venv/bin/activate
|
|
303
|
+
uv pip install maturin '.[all]'
|
|
304
|
+
maturin develop --release
|
|
305
|
+
pytest ethllama/tests/ -v
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### Formatter
|
|
309
|
+
|
|
310
|
+
The flake exposes `nixfmt-rfc-style` as the default formatter. Run
|
|
311
|
+
`nix fmt` to reformat the flake in place.
|
|
312
|
+
|
|
313
|
+
### Adding new tools
|
|
314
|
+
|
|
315
|
+
When you discover a new build/runtime dependency that the shell is missing,
|
|
316
|
+
add it to the `buildInputs` list in `devShells.default`. Keep the comments
|
|
317
|
+
grouped by purpose (Rust / Python / native / compilers / GPU) so the list
|
|
318
|
+
stays readable as it grows.
|
|
319
|
+
|
|
320
|
+
## Cross-Session Context Tips
|
|
321
|
+
|
|
322
|
+
- The `engines.py` `EngineConfig` class with Jinja2 templating is the **extension mechanism** for custom engines — this is the plugin system
|
|
323
|
+
- When adding new subcommands, add them to `cli.py`'s `@click.group()` and re-export from `__init__.py`
|
|
324
|
+
- When extending the Rust FFI, always add the `extern "C"` declaration to `llama.rs`, then wrap it in a safe function, then expose via PyO3 in `lib.rs`
|
|
325
|
+
- The `__all__` in `__init__.py` must be kept in sync with exports
|
|
326
|
+
- `pyproject.toml` at repo root uses maturin, and the `[tool.maturin]` section configures how the Rust crate is built (manifest-path points to `ethllama-core/Cargo.toml`)
|
|
327
|
+
- Always use `options = ["pyo3/extension-module"]` in `[features]` (no "pyo3" prefix for maturin — just the feature name)
|
|
328
|
+
- Run `pip install -e ".[all]"` to install all optional dependencies for development
|
|
329
|
+
|
|
330
|
+
## Future Roadmap (from initial Mistral Vibe discussion)
|
|
331
|
+
|
|
332
|
+
These features were discussed and are planned for post-MVP phases:
|
|
333
|
+
|
|
334
|
+
### Modality Expansion (Phase 2+)
|
|
335
|
+
- **whisper.cpp** — STT/TTS engine via `EngineConfig` (example YAML already in `docs/examples/whisper-cpp.yaml`)
|
|
336
|
+
- **stable-diffusion.cpp** — image generation (add as engine type `image`)
|
|
337
|
+
- General pattern: new backends = create `/path/to/engine.cpp` → write engine YAML → done
|
|
338
|
+
|
|
339
|
+
### Multi-GPU Support
|
|
340
|
+
- Not yet implemented in the Rust core or CLI
|
|
341
|
+
- Important for larger models on multi-GPU workstations
|
|
342
|
+
|
|
343
|
+
### Async Support
|
|
344
|
+
- Rust core could support async via `tokio` for concurrent inference
|
|
345
|
+
- Python side could use `asyncio` for non-blocking API endpoints
|
|
346
|
+
- Not yet implemented
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to **ethicallama** are documented in this file.
|
|
4
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
5
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- GitHub Actions CI workflow (`.github/workflows/ci.yml`) testing
|
|
11
|
+
Python 3.10 – 3.13 on `ubuntu-latest` (Rust + Python, with rustfmt/clippy lint job).
|
|
12
|
+
- GitHub Actions release workflow (`.github/workflows/release.yml`) that builds
|
|
13
|
+
manylinux + musllinux + macOS wheels via cibuildwheel, produces an sdist,
|
|
14
|
+
attaches everything to a GitHub Release, and publishes to PyPI using
|
|
15
|
+
**OIDC trusted publishing** (no API token in secrets).
|
|
16
|
+
- `[project.scripts]` entry exposing the `ethllama` CLI on `pip install`.
|
|
17
|
+
- `[project.urls]` block with Homepage / Repository / Issues / Changelog links.
|
|
18
|
+
- `[tool.cibuildwheel]` configuration in `pyproject.toml` (build matrix,
|
|
19
|
+
`MATH_BACKEND=openblas` for manylinux, pinned `pytest` test-requires).
|
|
20
|
+
- `[tool.pytest.ini_options]` section (`testpaths`, `asyncio_mode = "auto"`).
|
|
21
|
+
- PyPI / CI / License / Python-version badges at the top of `README.md`.
|
|
22
|
+
- `MANIFEST.in` controlling sdist contents (excludes `ethllama-core/target`,
|
|
23
|
+
`llama.cpp-build`, the bundled `ethllama-core/llama.cpp` submodule,
|
|
24
|
+
`.slim`, and `.benchmarks`).
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
- `pyproject.toml` moved from `ethllama/pyproject.toml` to the repository root
|
|
28
|
+
(the standard maturin layout). All `[tool.maturin]` paths were already
|
|
29
|
+
written relative to the project root, so no path edits were needed.
|
|
30
|
+
- `requires-python` bumped from `>=3.9` to `>=3.10` to match the CI matrix
|
|
31
|
+
and the README's stated prerequisites.
|
|
32
|
+
|
|
33
|
+
## [0.1.0] - 2026-07-03
|
|
34
|
+
|
|
35
|
+
### Added
|
|
36
|
+
- **CLI** (`ethllama.cli`) — 11 subcommands built on Click:
|
|
37
|
+
- `run` — run inference against a local GGUF model
|
|
38
|
+
- `pull` — pull a model from HuggingFace Hub
|
|
39
|
+
- `list` — list indexed models
|
|
40
|
+
- `index` — add / remove / list models in the local model index
|
|
41
|
+
- `config` — load, save, and initialise `~/.ethllama/config.yaml`
|
|
42
|
+
- `serve` — start the local FastAPI server
|
|
43
|
+
- `engines` — list and inspect configured engines
|
|
44
|
+
- `quantize` — quantise a GGUF model via `llama-quantize`
|
|
45
|
+
- `transcribe` — speech-to-text via a whisper.cpp engine
|
|
46
|
+
- `info` — show GGUF model metadata
|
|
47
|
+
- `rm` — remove a model from the index
|
|
48
|
+
- **FastAPI server** (`ethllama.api`) — opt-in OpenAI-compatible endpoints:
|
|
49
|
+
- `POST /v1/chat/completions`
|
|
50
|
+
- `POST /v1/completions`
|
|
51
|
+
- `POST /v1/embeddings`
|
|
52
|
+
- `GET /v1/models`
|
|
53
|
+
- `GET /health`
|
|
54
|
+
Supports optional bearer-token auth, streaming responses, and is gated
|
|
55
|
+
behind the `ethllama[api]` extra.
|
|
56
|
+
- **Real inference** — `ethllama.inference` shells out to `llama-cli` /
|
|
57
|
+
`llama-embedding` binaries when the Rust core is unavailable, so the
|
|
58
|
+
package works out-of-the-box for any user with a llama.cpp checkout.
|
|
59
|
+
- **Rust FFI core** (`ethllama-core/`) — PyO3 bindings to llama.cpp
|
|
60
|
+
covering model loading, context creation, tokenisation, and a full
|
|
61
|
+
sampler chain (greedy / temperature / top-p / top-k / dist).
|
|
62
|
+
- **Model pulling**:
|
|
63
|
+
- HuggingFace Hub backend (`ethllama[pull]`, `huggingface_hub`)
|
|
64
|
+
- Ollama registry backend (built-in, OCI Distribution Spec v2, no auth
|
|
65
|
+
required for public models on `registry.ollama.ai`; the
|
|
66
|
+
`application/vnd.ollama.image.model` blob is the raw GGUF, no
|
|
67
|
+
conversion needed).
|
|
68
|
+
- **Model quantisation** — built-in `ethllama quantize` command calling
|
|
69
|
+
`llama-quantize` (11 quant types, default `q4_k_m`).
|
|
70
|
+
- **Embeddings endpoint** — `POST /v1/embeddings` returning deterministic
|
|
71
|
+
768-dim vectors (stub until the Rust core exposes a real embedding API).
|
|
72
|
+
- **GPU selection flags** — `--gpu {vulkan,rocm,cuda,cpu}` and
|
|
73
|
+
`--gpu-layers <N>` on the `run` command; auto-detection order
|
|
74
|
+
Vulkan → ROCm → CUDA → CPU.
|
|
75
|
+
- **Async API** — FastAPI endpoints are async; the API layer exposes
|
|
76
|
+
`async def` handlers and uses `uvicorn[standard]`.
|
|
77
|
+
- **Pluggable engine system** — `ethllama.engines.EngineConfig` loads
|
|
78
|
+
YAML files from `~/.ethllama/engines/` and renders CLI invocations via
|
|
79
|
+
Jinja2 templates; ships with examples for `llama-cpp`, `whisper-cpp`,
|
|
80
|
+
and a generic custom engine.
|
|
81
|
+
- **Engine YAML examples** in `docs/examples/` (`llama-cpp.yaml`,
|
|
82
|
+
`whisper-cpp.yaml`, `custom-engine.yaml`).
|
|
83
|
+
- **Nix development shell** (`flake.nix`) — reproducible dev environment
|
|
84
|
+
with Rust toolchain, Python 3, maturin, cmake/ninja, openssl, and
|
|
85
|
+
Vulkan headers pre-installed; auto-initialises the `llama.cpp`
|
|
86
|
+
submodule on first entry.
|
|
87
|
+
- **Documentation** — `README.md`, `docs/USAGE.md`, `docs/PRIVACY.md`,
|
|
88
|
+
`docs/CREDITS.md`, `AGENTS.md` (project memory for coding agents).
|
|
89
|
+
- **Python test suite** — 76 tests across `test_cli.py`, `test_api.py`,
|
|
90
|
+
`test_stt.py`, covering the CLI surface, the FastAPI server, the
|
|
91
|
+
whisper.cpp STT path, the model index, and the engine registry.
|
|
92
|
+
- **Setup / benchmark scripts** — `scripts/setup.sh` and
|
|
93
|
+
`scripts/benchmark.sh` for one-command environment bring-up and
|
|
94
|
+
timed inference benchmarking.
|
|
95
|
+
|
|
96
|
+
### Notes
|
|
97
|
+
- This is the first public release of **ethicallama**.
|
|
98
|
+
- Inference runs **fully locally**. The only network calls the package
|
|
99
|
+
makes are to HuggingFace / Ollama when you explicitly invoke `pull`.
|
|
100
|
+
- Telemetry is **off by default**; the only outbound traffic is model
|
|
101
|
+
pulls, and they are user-initiated.
|
|
102
|
+
|
|
103
|
+
[Unreleased]: https://github.com/your-org/ethicallama/compare/v0.1.0...HEAD
|
|
104
|
+
[0.1.0]: https://github.com/your-org/ethicallama/releases/tag/v0.1.0
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Credits
|
|
2
|
+
|
|
3
|
+
ethicallama is built on the following open-source projects:
|
|
4
|
+
|
|
5
|
+
- **[llama.cpp](https://github.com/ggerganov/llama.cpp)** (MIT License)
|
|
6
|
+
- Used for GGUF model loading and inference.
|
|
7
|
+
- Original work by Georgi Gerganov.
|
|
8
|
+
|
|
9
|
+
- **[whisper.cpp](https://github.com/ggerganov/whisper.cpp)** (MIT License)
|
|
10
|
+
- Used for speech-to-text and text-to-speech (future).
|
|
11
|
+
|
|
12
|
+
- **[PyO3](https://github.com/PyO3/pyo3)** (Apache 2.0/MIT)
|
|
13
|
+
- Used for Rust-Python bindings.
|
|
14
|
+
|
|
15
|
+
- **[FastAPI](https://github.com/tiangolo/fastapi)** (MIT License)
|
|
16
|
+
- Used for the HTTP API.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 luluthehungrycat
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|