518 Commits

Author SHA1 Message Date
ZacharyZcR 1d9f554715 cuda: cache layernorm weights on-device in pipe_layer_sparse (kill 152 sync H2D/token) + overlap-window profiling counters 2026-07-19 23:19:25 +08:00
ZacharyZcR ab55f4900c cuda: COLI_GROUP_ASYNC=1 — async expert-group issue/take with CPU/GPU overlap at decode (opt-in, +6-8% measured) 2026-07-19 23:19:25 +08:00
Nicholas Beerbower 4586d33c60 fix: MTP-head probe uses the last expert by index, not a hardcoded 255
The has_mtp completeness probe checked for `mlp.experts.255.down_proj.weight`,
which only exists when n_routed_experts == 256. REAP-pruned checkpoints (and any
MoE with a different expert count) have fewer experts, so the probe spuriously
reported has_mtp=0 and disabled MTP speculative decode even though the head was
present and complete. Probe `mlp.experts.<n_experts-1>` instead.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-19 10:54:01 -04:00
Davide Quack 27b4c4263a Added Dockerfile and instructions for using Colibrì through a docker container 2026-07-19 16:49:29 +02:00
Steve Markgraf e9225d2ffc docs: dual-SSD streaming env vars in ENVIRONMENT.md 2026-07-19 15:52:06 +02:00
Steve Markgraf 63966ba3f8 Dual-SSD streaming: COLI_MODEL_MIRROR reads experts from two model copies
A second (read-only) copy of the model on another drive is registered as a
per-shard read replica; expert loads are split between the drives by a
deterministic (layer,eid) hash weighted by COLI_DISK_WEIGHTS=<primary>,<mirror>
or, by default, by a startup bandwidth probe using the engine's own access
pattern (parallel ~19 MB reads, O_DIRECT). Cold decode is disk-bound
(~11 GB/token), so two NVMe queues add up.

- st.h: mirror accepted per file only if size + safetensors header are
  byte-identical to the primary (identical data_offsets by construction, so
  every pread is valid on either copy); partial mirrors work (smaller second
  SSD holding only some shards); the mirror is never written — .coli_usage /
  .coli_kv stay on the primary.
- glm.c: routing covers the coalesced slab pread, O_DIRECT, mmap/Metal and
  scale reads, plus the OMP-parallel pin/autopin warmup (streams from both
  drives). Deterministic routing keeps readahead/PILOT WILLNEED on the same
  drive as the demand read and avoids caching an expert twice. A mirror read
  error falls back to the primary (one warning, no crash). Per-drive bytes
  are reported in a MIRROR: stats line.
- tests: test_st_mirror covers validation, read equality on both replicas,
  and the rejection paths (divergent header, size mismatch, missing file).

Measured on 2x NVMe (GLM-5.2 int4, greedy, DRAFT=0, DIRECT=1, cold-ish
cache): 0.42 -> 0.57 tok/s (+36%), expert-disk service 15.2s -> 10.3s,
byte-identical output; probe chose a 48/52 split.
2026-07-19 15:52:06 +02:00
noobdev-ph 26d6b2d662 sync: dev 2026-07-19 21:47:34 +08:00
noobdev-ph 468b190db9 Merge remote-tracking branch 'upstream/main' into feat/gpu-backend-hardening 2026-07-19 21:39:57 +08:00
Vincenzo Fornaro 61004dcb84 Merge pull request #391 from ZacharyZcR/refactor/split-colibri
refactor: split glm.c → colibri.c + 4 header modules (−18%)
2026-07-19 15:29:40 +02:00
ZacharyZcR 8a9a0fca4d plan: auto-tune heuristics — bottleneck classification + parameter decisions
Extend resource_plan to classify the hardware into bottleneck regimes
(disk / memory / mixed / compute) and derive tuning knobs automatically:

  MTP:   off when compute-bound (42% loss at full residency, #389)
         or disk-bound with <90% hit (union growth adds reads)
  PIPE:  COLI_CUDA_PIPE=1 single-GPU, =2 multi-GPU, PIPE=1 CPU disk
  NUMA:  selective interleave for GPU hosts, blanket hint for CPU-only
  PIN:   PIN_GB=all when fully resident + no GPU
  OMP:   COLI_NO_OMP_TUNE=1 for Metal (spin steals GPU power)

`coli plan` now shows an auto-tune section with each knob and its
reason. `environment_for_plan()` applies them via setdefault so
explicit user settings always win.

plan version stays at 2 (additive fields: bottleneck_class,
projected_hit_rate, tune). 7 new tests covering all regimes.
2026-07-19 21:20:00 +08:00
ZacharyZcR 083fda5b0a fix: update test_logit_nan to include colibri.c instead of glm.c 2026-07-19 21:18:33 +08:00
ZacharyZcR bc69a9a6d0 fix: remove duplicate argmax_v — use NaN-safe version from sample.h 2026-07-19 21:15:54 +08:00
ZacharyZcR 93b4a8e78e ci: fix Windows CUDA DLL check — glm.exe → colibri.exe 2026-07-19 21:12:16 +08:00
ZacharyZcR e486574442 web: i18n support — English, 简体中文, 繁體中文, Italiano
Lightweight i18n without react-i18next: a LocaleProvider context +
useLocale() hook with {{var}} interpolation, auto-detect from
navigator.language, persisted to localStorage.

98 translation keys across 4 locale files (en/zh-CN/zh-TW/it).
All user-visible strings in App/Brain/Profiling/ErrorBoundary are
now t() calls. Language switcher added to the sidebar footer.

Build clean (tsc + vite), 18 tests pass.
2026-07-19 21:12:12 +08:00
ZacharyZcR 420a0720c3 docs: add simplified Chinese and Italian README, update language nav
New files:
  README.zh-CN.md — simplified Chinese (大陆用词)
  README.it.md    — Italian (the project's "mother tongue")

All four READMEs now link to each other in a consistent nav bar.
Updated zh-TW to reflect glm.c → colibri.c rename and new headers.
2026-07-19 21:12:11 +08:00
ZacharyZcR f853ea8a0b refactor: split glm.c into colibri.c + 4 header modules
Rename glm.c → colibri.c and extract four self-contained modules
into header-only files (same pattern as st.h/tier.h/grammar.h):

  quant.h      (672 lines) — SIMD matmul kernels, quantization
  sample.h     (143 lines) — RNG, top-p sampling, stop-set
  kv_persist.h (121 lines) — .coli_kv disk persistence
  telemetry.h  (189 lines) — dashboard protocol, stats, usage

Main engine file shrinks from 6588 to 5396 lines (−18%).

Build system: primary target is now colibri$(EXE); `make glm`
remains as a phony alias for backward compat. CI, setup.sh,
coli CLI, and all 10 test files that include the engine are
updated. make check passes (C + Python, 73 tests, zero warnings).
2026-07-19 21:12:04 +08:00
Vincenzo Fornaro 8f33bd153b Merge pull request #420 from JustVugg/p417-metal-lfru
metal: advance the LFRU recency clock on the GPU-prerouted decode path (#417)
2026-07-19 15:02:41 +02:00
JustVugg cfcc742591 metal: advance the LFRU recency clock on the GPU-prerouted decode path (#417)
On Metal, when routing is precomputed on the GPU (g_pre_idx), the moe fast
path bumps eusage/ehit/eheat for the selected experts but skips the one thing
the full CPU router does at the equivalent site: elast[layer][e] =
++eaccess_clock. So the session-local recency clock advances during prefill
(full router) but freezes the moment GPU-prerouted decode starts, and REPIN's
tier_pick_lfru() tie-breaker then runs on stale recency for the rest of the
run. Mirror the exact update the non-Metal path already does. Inside
#ifdef COLI_METAL, so CPU/CUDA are untouched; elast only feeds the LFRU
eviction heuristic, so this cannot affect output, only which experts REPIN
keeps warm.

Found and reported by @monotophic with a source-level trace repro
(ELAST_TRACE). Fix is inspection-verified against line ~3055; needs a
Metal build to exercise end-to-end.

Closes #417

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 14:58:32 +02:00
Vincenzo Fornaro ebc851edb3 Merge pull request #415 from JustVugg/docs-quickstart
docs: beginner-friendly Quick Start guide (#414)
2026-07-19 14:25:24 +02:00
Attila Oláh 40a3596354 nix: python3 is only needed for checks, not for the actual build 2026-07-19 14:09:45 +02:00
JustVugg 845af6378d docs: beginner-friendly Quick Start guide for Linux/Windows/macOS (#414)
Adds docs/quickstart.md — a step-by-step, no-experience-assumed walkthrough
from installing the build tools to the first coli chat, with per-OS
copy-paste commands (Ubuntu apt, Windows MSYS2 or prebuilt binary, macOS
brew), the ready-made HF int4 container plus the self-convert path, and an
honest 'what to expect' on disk-bound speed. Commands verified against
setup.sh and the coli subcommands; every cross-linked doc exists. Linked
from the README's Get started section.

Closes #414

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 14:08:19 +02:00
Attila Oláh 4775f28ceb nix: copy missing version.py to the environment 2026-07-19 13:50:45 +02:00
Attila Oláh 51fe03f615 nix: set main program to coli
This is the higher-level user interface, which should be the main entry point to the binary, not the engine itself. The engine is still available.
2026-07-19 13:39:02 +02:00
Attila Oláh da97f0dbf1 nix: build on darwin with -march=native 2026-07-19 13:37:57 +02:00
Attila Oláh 58fd0e557f nix: commit lockfile, ignore result
This makes the build actually reproducible by committing a working lockfile to the repo.
2026-07-19 13:37:54 +02:00
Attila Oláh bcb984a61f nix: use getExe instead of hardcoding the path 2026-07-19 13:37:22 +02:00
Attila Oláh e93d574e13 nix: add the python env to check inputs
The tests now require Python so the env should be added to the check
inputs, otherwise the build fails.
2026-07-19 13:37:21 +02:00
Attila Oláh a6d0a6c4a7 nix: use with pkgs in some package lists 2026-07-19 13:37:20 +02:00
Attila Oláh 73aef4d010 nix: configure and apply a formatter
This sets the formatter to alejandra. I was trying to stay as close as
the original as I could; otherwise we could set it to `nixfmt` which
would keep list spacing more similar, but would introduce additional
indentation in a few places.
2026-07-19 13:36:30 +02:00
Attila Oláh ac39be6b62 flake: remove unnecessary rec 2026-07-19 13:35:26 +02:00
Vincenzo Fornaro 3ffe4bb75e Merge pull request #413 from JustVugg/p-sec-trustboundary
security: reject malformed model tensors at the untrusted-mirror boundary (C half of #368)
2026-07-19 13:11:06 +02:00
JustVugg 72e36772f5 security: reject malformed model tensors at the untrusted-mirror boundary
Colibri loads model directories and safetensors from mirrors it does not
control, so the file's declared shapes and byte spans are attacker-influenced
input. Three memory-safety holes on that boundary, independently confirmed
(incl. a from-scratch adversarial audit that re-derived the same two) and
present in the shipped v1.0.0:

- st.h st_read_f32: numel came from the shape, nbytes from the offsets, with
  no cross-check. A crafted tensor whose shape inflates numel past nbytes made
  the BF16/F16 loop read past the malloc'd raw buffer and the F32 memcpy write
  past the caller's config-sized destination (heap OOB read + write). Now
  enforce numel*esz == nbytes before any copy.
- st.h header parse: the shape product could overflow int64 to a small/negative
  numel that would then pass the cross-check. Guard each multiply.
- glm.c qt_resolve_fmt (new, replaces the three duplicated "?1:?2:3" fmt sites
  in qt_from_disk and both expert_load arms): the old inference SILENTLY fell
  to int2 for any unrecognized weight byte count, so a too-short weight became
  a valid int2 whose matmul read O*I nibbles past the buffer; and an oversized
  scale array overflowed the per-row t->s. Now the weight bytes must match a
  known int8/int4/int2 layout and the scale array must match the expected
  per-row (O) or grouped (O*ng) cardinality, else refuse.
- glm.c config/generation_config slurp: unbounded ftell -> malloc(n+1) gave a
  hostile file a load-time OOM, and on malloc failure b[got]=0 was a NULL
  deref. Cap at 256 MB and NULL-check.

Verified: TF token-exactness unchanged on every quant format (full-precision
32/32, int4 11/32, int2 1/32, mix 5/32 -- byte-identical to the pre-change
binary); fmt=4 grouped path preserved (the scale check is by construction the
same condition detect_group_size already imposed); a hand-crafted hostile
safetensors is refused cleanly; ASan+UBSan clean on legit and hostile loads
(only the pre-existing intentional startup leaks remain).

These are the C trust-boundary items of #368, landed as a minimal standalone
fix; the server-side and build items of that PR follow via its rebase.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 13:06:35 +02:00
Vincenzo Fornaro fae4b2cc3e Merge pull request #412 from JustVugg/p396-packaging
packaging: pyproject + editorconfig + clang-format (#396) with a single version source
2026-07-19 12:42:29 +02:00
JustVugg 22509fccde Merge pull request #362 from EgonRuiter/prefetcher-v3
feat(prefetch): async expert prefetcher v3.2 for the OLMoE testbed

Testbed-only scope: olmoe.c + tools/oracle files; glm.c untouched (the
production engine already ships the equivalent techniques: coalesced slab
preads, PILOT lookahead, persistent PIN). Trivial .gitignore conflict
resolved keeping both sides.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 12:40:43 +02:00
JustVugg ca39e5333f packaging: single version source + honest editable-install semantics (on top of #396)
colibri/_version.py now reads c/version.py (#394's single source of truth --
coli --version, the release workflow, and pip metadata can no longer drift),
with an importlib.metadata fallback for the installed-wheel case where c/ is
not on disk. README documents that pip install -e . is the supported form:
the engine lives in c/ and is not packaged into a standalone wheel.

Verified in a clean venv: pip install -e . -> colibri.__version__ == 1.0.0
read from c/version.py, coli entrypoint on PATH and functional.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 12:38:11 +02:00
JustVugg 741d46ba25 Merge branch 'pr396' into p396-packaging 2026-07-19 12:36:18 +02:00
Vincenzo Fornaro 72874f38a2 Merge pull request #411 from JustVugg/dev
release: fix the Windows job shell in release.yml (v1.0.0 tag build)
v1.0.0
2026-07-19 12:30:32 +02:00
JustVugg 3cd2674f68 release: fix the Windows job shell — 'msys2 {0}', not 'msys2' (+ inherit PATH for 7z)
GitHub Actions shells are format strings; the bare 'msys2' string made the
v1.0.0 tag build fail before its first step ('Invalid shell option'). Same
invocation ci.yml already uses. path-type: inherit so the Package step can
reach the runner's 7z.exe.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 12:29:33 +02:00
Vincenzo Fornaro 819941ee2c Merge pull request #400 from JustVugg/dev
Release v1.0.0
2026-07-19 12:25:43 +02:00
Vincenzo Fornaro e25aeecc4c Merge pull request #410 from JustVugg/p403-rss-guard
glm: measured-RSS guard — the RAM budget enforces itself at the safe point (#403)
2026-07-19 11:29:11 +02:00
Vincenzo Fornaro 2f8fefd701 Merge pull request #408 from JustVugg/p401-tools-e2e
serve: end-to-end tool-calling regression test + unparsed-marker diagnosis (#401)
2026-07-19 11:06:14 +02:00
JustVugg c90e2cc438 glm: measured-RSS guard — the RAM budget enforces itself at the safe point (#403)
cap_for_ram's projection is an estimate: on the GB10 (#403) long generations
overshot it by ~40 GB (projected 74.4, real 115.6) and the kernel killed the
engine three times. Run D of the issue proves a low cap CONTAINS the growth;
this guard does that automatically, keyed on MEASURED RSS instead of the
projection.

At the repin safe point (no moe in flight), every ~16 emitted tokens: if RSS
exceeds the resolved budget (RAM_GB/auto, or an explicit RSS_GUARD_GB
ceiling), free the least-used LRU expert slabs in place and lower ecap so the
cache cannot regrow. Slabs are >128 KB so glibc returns the pages to the
kernel immediately -- RSS actually drops.

Eviction never compacts the array: with PILOT_REAL the pilot worker holds
pointers into ecache[] across its preads, so the slot stays in place with
eid=-1/used=0 (first candidate for reuse); reserved slots (eid<0) are never
touched and victim selection happens under g_pilot_mx. resident_bytes is left
alone: LRU slots are never accounted there (only pin + dense).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 11:02:31 +02:00
JustVugg 0f606bc446 test: skip the tools e2e suite on Windows (shebang mock engine)
CreateProcess cannot exec a shebang script, so the gateway exits during
setUpClass on the windows CI job. The gateway logic under test is
platform-independent and stays covered by the POSIX jobs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 11:01:26 +02:00
JustVugg 2122c004d9 serve: end-to-end tool-calling regression test + unparsed-marker diagnosis (#401)
The gateway's tool-calling path had unit coverage (parse_tool_calls,
render_chat) but nothing exercised the real subprocess wire protocol or the
HTTP surface a coding client actually hits. #401 reports plain-text replies
where tool_calls were expected; every documented path checks out, so pin the
whole path down with a mock engine speaking SUBMIT/DATA/DONE and assert:

- non-stream: tool_calls populated, finish_reason tool_calls, no raw markers
- stream: markers suppressed across 20-way chunk splits, tool_calls delta
- tool-result round trip: <|observation|><tool_response> rendering, text reply
- no tools: plain text untouched

Also emit a stderr diagnosis when tools are declared and tool-call markers
are present in the reply but the strict parse matches nothing (typically
quantization-mangled output) pointing at COLI_TOOL_SALVAGE=1 -- the likely
field condition behind #401.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 10:56:00 +02:00
JustVugg d94c68149d Merge pull request #352 from woolcoxm/fix/test-stops-windows
fix(test): make test_stops build on Windows (mkdtemp compat shim)

Conflict with #366's getenv_utf8 in compat.h resolved by keeping both blocks.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 10:42:41 +02:00
Vincenzo Fornaro 66b5e57bc4 Merge pull request #397 from NeuralNotwerk/fix/mtp-int8-repair
tools: repair int4-converted MTP heads in place; warn on --mtp --ebits <8
2026-07-19 10:40:07 +02:00
Vincenzo Fornaro 3f99d2bbb7 Merge pull request #395 from Stonki13/fix/windows-cuda-detection
Fix CUDA detection on Windows (coli/doctor.py always report CPU-only)
2026-07-19 10:40:01 +02:00
Vincenzo Fornaro 19bab420a0 Merge pull request #404 from anrasi/fix/indir-meta-resume
convert(fp8->int4): --indir copies the full metadata set and resumes interrupted passes (#383)
2026-07-19 10:39:56 +02:00
Vincenzo Fornaro 36d389bf50 Merge pull request #402 from anrasi/fix/coli-run-think
coli: honor THINK=1 in run mode
2026-07-19 10:39:50 +02:00
JustVugg 6690c4f58e Merge branch 'p394' into trialsafe 2026-07-19 01:28:16 +02:00