96 pull requests since v1.12.0, 80 of them from contributors. Two tokenizers
brought back to the reference, brio on the ninth engine, coli chat working
again at the default context on two families, and a placement decision that
is now measured on the card in front of it instead of predicted.
Tokenizers, measured against the reference
- #1654: qwen36 tokenized differently from HF
tokenizersin two ways.
An added token right after punctuation was encoded as text (X.<|im_end|>
was 7 tokens instead of 3, every chat turn ending in punctuation paid +4,
#1653), and a whitespace run followed by a non-space was one piece where
the regex's\s+(?!\S)leaves the last char to the next one, so every
indented line of code tokenized differently. Measured on the real
vocabulary: 2,803 lines and blocks of code, Markdown, Chinese and
Japanese went from 757 identical to 2,803, with 5.4% fewer tokens. - #1656: OLMoE's
tokenizer.jsonhas no Split, a bare ByteLevel with
use_regex, for which HF runs the original GPT-2 pattern;tok.happlied
cl100k. A GPT-2 family intok.h: 1,560/1,708 identical before, 1,708/1,708
after. The same measurement on GLM-5.2/5.3/5.3-Flash, DeepSeek V4 and V4.1,
Inkling and Qwen3.8 came back identical on every case.
Brio and the serve contract
- #1662:
POST /v1/systemone, the request and the reply of TypeSafe's
Jev API, served by the brio channel: a client written for it points at
colibri and changes the base URL.noulis a yes/no question,choice
scores the labels with their descriptions in the text,scorethe level
numbers with the expected value and the legend;confidenceby their
documented formula. Anymodelname is accepted on that route. Measured on
the real Qwen3.6: the three-question example of the docs in 1m46 with the
state read once. - #1655: the DeepSeek V4 engine speaks the numeric channel (
logprobs=k,
pin=1,max_tokens=0), so/v1/brioworks on the ninth engine instead
of answering 500 (#1648). The head that used to keep only its argmax now
returns the whole row;ECHOper prompt position during prefill, the
prompt-end scores kept with a state snapshot onpin, and a logprob tail
on everyDATAframe during generation. The tiny fixture pins that the
bestECHOtoken equals the greedy token from the same prefix, and that
the pinned predictor equals a cold prefill's. - #1659: qwen36 and qwen38 refused a request when
prompt + max_tokens
exceeded the context, and the gateway's default budget for these two
families is 8192, the whole default context: every request without
max_tokensand everycoli chatmessage answered 400 on a two-token
prompt (#1641).max_tokensis now a ceiling, clamped to the room the
prompt leaves, as GLM and DeepSeek V4 already did; only a prompt that does
not fit is refused.docs/api.mdstates the rule,docs/qwen38.mdnames
Q38_MAXTas the variable--ctxbecomes.
The dense trunk in VRAM, measured before it is placed
- #1657: qwen36 offers the rest of its dense trunk to the VRAM placer:
the DeltaNet out_proj (dnout), the attention q/k/v/o (attnproj) and
the shared expert (shexp), about 650 MB more of int8 on the 35B beside
lmheadanddnproj. Measured on four Tesla M10 by the reporter of
#1652, every placed component ran slower than the CPU (lm_head 68.8 ms
against 41.7), so the engine now times one GEMV both ways at startup and
withdraws the whole automatic placement when the GPU loses, giving the
VRAM back to the experts:autoequalsoffon that box, byte-identical
output. A hand-writtenCOLI_PLACEstands;COLI_TRUNK_PROBE=0trusts
the placer.
Performance
- #1664: qwen36's dense trunk and routed experts multiply with integer
dot products. The activation is quantized to int8 once per call and the
weights, int8 rows or int4 planar blocks, meet it with maddubs / vpdpbusd
instead of a float conversion per weight; the integer kernels move from
quant.hintoidot.h, shared by every engine. Measured on the 35B, 8
threads, every expert resident: decode 6.71 to 8.23 tok/s (+22.6%), lm_head
12.6 to 10.1 ms/token, the expert compute 22.7 to 15.6, for +1.3%
perplexity on 4 x 512 tokens. Both are the default (COLI_DENSE_IDOT=0,
QWEN_EXPERT_ACT=f32restore the f32 kernels).COLI_DENSE_BITS=4with
COLI_DENSE_INT4=<components>stores part of the trunk as int4 in blocks
of 64: opt-in, with the perplexity it costs per component in the docs
(lm_head alone +2.4%, everything +10%). - #1668: qwen38's dense trunk (553 matrices, 3.6 G weights, 8 GiB of
BF16 read on every token, more than the ten routed experts) is kept on the
CPU as int8 rows with the BF16 copy released, and multiplied with the same
integer kernels; the routed experts' e4m3 blocks are decoded eight at a
time in registers and multiplied with FMA instead of one table lookup per
weight. Measured on the released Qwen3.8-Flash-Next-FP8, 8 threads, RAM
LRU 96 per layer: decode 0.61 to 1.42 tok/s, the trunk 434 to 85 ms/token,
lm_head 76 to 13, the expert GEMVs 388 to 140, peak RSS 32.2 to 28.5 GB;
prefill of 512 tokens 495 to 149 s. Perplexity on 4 x 512 tokens +0.5%
(two chunks lower, two higher); the vector FP8 kernel alone reproduces the
BF16 run to four decimals. Both are the default (Q38_TRUNK_CPU_INT8=0
keeps the BF16 trunk,Q38_FP8_KERNEL=scalarthe table kernel).
Performance, from contributors
- #1606: the K1b grouped int4 family gets a multi-row tile and AVX-512
and AMX arms, and is no longer switched off on AVX-512 builds; exact on
all eight engines on a 16-core AVX-512 host. - #1239: an SSE4.1 tier for the olmoe and qwen36 int8 GEMV, for hosts
with SSE4.1 but no AVX2; on the Sandy Bridge of #1652 decode went from
2.45 to 3.54 tok/s. - #1313:
matmul_fp8computes four output rows per pass under clang,
where the contraction makes it bit-exact; GCC keeps the one-row kernel. - #1612: qwen36 gains the GLM engine's
CACHE_ROUTElever, with the
VRAM tier as the first residency level, opt-in. - #906:
DEGRADE_ZERO, an opt-in policy that zero-fills a missed
expert slot below a gate-weight threshold instead of blocking on the
load (#865). - #1677: qwen36 projects a prompt's DeltaNet inputs (qkv and z) on the
card in blocks of up to 256 rows instead of one row at a time; a 259-row
prefill makes 2 projection calls instead of 259, with the convolution
history and the recurrent state checked against the CPU run. The paired
microbenchmark on an RTX 4070 read 4 to 10x per projection. - #1674: qwen36's attention projections the tier placed in VRAM answer
a whole prompt batch with one call per matrix; a failed call turns only
that handle off and the prompt continues on the CPU. - #1676: Kimi K3's streaming CUDA expert keeps the gate, up and SiTU
intermediates on the device and applies down there (one fused entry
point, optional in the DLL: an older backend keeps the three-call path). - #1673: the streaming MXFP4 matmul reuses one grow-only device scratch
per card instead of allocating and freeing weights and scales on every
call. - #1559 (kreuzzelg):
convert_qwen36.py --down-bits 8writes the mixed
expert layout, int4 gs64 gate/up and int8 down in one slab (5.7 bits per
weight against gs64's 4.5); the engine tells it apart by size and reads
each matrix in its own format on the CPU path, and refuses the VRAM tier
with a line. It is the knob behind the #1370 numbers: on wikitext-2 the
int8 down alone recovers a quarter of the gap between gs64 and all-int8,
the rest sits in gate/up. A measurement tool and a middle step, not the
answer to the gap. - #1730 (mfethe1): DeepSeek V4's FP4 expert kernels, the prefill batch
and the decode matvec, get a NEON arm; arm64 used to take the scalar
arm, which is why Apple Silicon prefilled at decode speed (#1696). Bit
identical to the scalar arm, and the ARM CI job now checks that on every
change; 17 to 22x on the kernel at the V4 expert shapes on an M-series
Mac, as measured by the author. - #1716 (jtinbergen): qwen36 quantizes its dense weights to int8 while
loading instead of keeping an f32 copy first, and converts f16/bf16 with
SIMD. On the 35B the resident set after load goes from 9.2 to 4.8 GB;
the generated text and the perplexity are identical to before. - #1286 (cameron): the grouped int4 GEMV and the fused gate/up GEMV get
an SSE4.1 arm for CPUs without AVX2 (Ivy Bridge and older). It vectorizes
across output rows, so each lane runs the scalar row's exact sequence and
the result is bit-identical; forced-SSE4.1 tests at -O1, -O3 and without
FP contraction pin it. 2.2 to 2.7x on the isolated kernel on a dual
E5-2680 v2. - #1686 (DebugSultan): qwen38's prefill chunk (
Q38_PREFILL_BATCH_ROWS)
and workspace (Q38_PREFILL_WORKSPACE_MIB) are runtime knobs, the expert
load batch is no longer capped at top-k, and the QSA ranking and
attention run per position in parallel at prefill. Measured on the
released checkpoint on top of the int8 trunk: output byte-identical at
every chunk width, no speed change on our 16-core server; the knobs are
there for hardware where the chunk binds.
Fixed
- #1650 (bokiko): a Qwen3.8 pin snapshots the recurrent and PLE state
but reuses the live attention and indexer rows; after an unrelated prompt
overwrote those rows, returning to the pin could change brio logprobs
without a warning. The engine now records the token identity of the live
rows (kv_prefix.h) and refuses a stale pin or prefix restore; image rows
are tainted. Wire regressions run on the BF16 and FP8 fixtures. - #1626:
SNAPis the model directory for every non-GLM engine, so
coli runstops handing them a leftover environment (#1600). - #1604: glm53 honours
Mat.residentin the Vulkan gate and frees the
Vulkan handle inmat_release. - #1321: glm53 sizes its expert cache around the model rather than
aroundMemAvailable, which the page cache had been inflating. - #1588: qwen36 refuses loudly on a failed encode-buffer realloc instead
of writing through NULL. - #1546:
coli convertroutes OLMoE toconvert_olmoe_merged.py. - #1630: olmoe emits the
ROUTE_TRACErecords it announced; the stream
used to be a zero-byte file. - #1610:
v41_dsml.pyis staged during installation (and the nix flake
bumped). - #1511: the GPU test suite builds under HIP on gfx1151.
- #1658:
test_mem_availablecompared two reads of available memory
with==and failed on a busy Windows runner; a quarter of a GB of
tolerance. - #1670: DeepSeek V4.1 read only its argv cache cap, so
RAM_GB=120
on a 128 GB box left the engine at eight expert slots per layer and
23.8 GB of RSS (#1666). With--capomitted,coli chat,coli serve
andcoli webnow size the cache from the resource plan, withRAM_GB
or--ramas the budget; an explicit--cap, a measured profile and an
auto-tier plan keep precedence. - #1671: DeepSeek V4.1 treats
max_tokensas a ceiling like the other
engines (#1641): a fitting prompt with a large request generates what
the context leaves, a score-only prompt may fill the context, and a
prompt one token over it is refused instead of silently truncated. - #1675: resident MXFP4 tensors on CUDA carried O float scales where
the kernel reads O x ceil(I/32) exponent bytes: short buffers were
over-read and long ones truncated. One format-aware size for upload,
refresh, accounting and release. - #1678, #1679, #1680, #1682, #1683, #1684: the
Qwen CUDA tier's lifecycle, end to end. Shutdown releases every resident
expert, projection handle and host table after parked callers resume;
a failed gate, up or down upload frees what it had already allocated;
the expert budget charges the three scale buffers at their own sizes
(two experts used to be admitted where one fit); a failed result
collection stops inference instead of publishing a partial MoE sum; a
failed or explicitly disabled tier start unwinds its storage and
synchronization objects, and a second init cannot overwrite a running
tier; the CUDA backend validates the whole device list before touching
state and keeps live contexts on a repeated init. Fault-injected on the
fake backend, then run together on an RTX 4070 under compute-sanitizer
with zero errors and zero bytes leaked. - #1669:
test_systemone_apiimports its scoring engine relative to
its package, so an installedtestspackage no longer breaks discovery. - #1697 (kevin9327): the dashboard redesign had dropped the reasoning
stream: thinking tokens arrived ondelta.reasoning_contentand vanished,
the bubble stayed empty until the answer and a stop during thinking lost
the turn. The stream is read again, rendered as its own folding block,
counted in the rate and the time to first token, and a unit test pins the
split. - #1693 (namespaceMarcello): with
PILOTon, OLMoE could read the same
expert twice, once from the prefetcher and once from the forward pass,
into two slots; a slot being read now keeps a reservation in the index
(thecolibri.cpattern) and the second caller waits for the first read
to publish. Three model-free scenarios pin it. - #1695 (namespaceMarcello): the prefill echo state and
serve_echosit
under the sameQWEN36_NO_MAINguard, so the segment build no longer
warns about a function it never gets; the full build is byte-identical. - #1724 (GenericRikka): Qwen3.6 decoded
<think>,</think>and the
tool tags to nothing, because they live only in the tokenizer's
added_tokens; with thinking on, the closing tag never reached the
gateway and the whole answer came back asreasoning_content. The
non-special added tokens are decoded now; special ones such as
<|im_start|>still decode to nothing. - #1734 (tarazum): stopping
coli servecloses the engine's stdin and
waits for it to exit on its own before the hard-stop ladder, so the
engine's teardown runs; qwen36 never saved itsHEAT_FILEundercoli serve(#1733). On Windows the gateway handles SIGBREAK and the engine
runs in its own process group. - #1726 (kevin9327): Inkling measured no RAM on Windows and sized its
expert cache to 16 per layer; it uses the shared probe now, which on
Linux and macOS reads the same numbers as before. - #1735: on GNU Make 3.81, the system make on macOS,
.build-config
was never written and every build relinked (#1732). - #1731 (bokiko): the DeepSeek V4 CUDA object rebuilds when the nvcc
command changes, so a newCUDA_ARCHno longer links the old object. - #1728 (crichalchemist):
make test-c VK=1built 43 test binaries
without the Vulkan object; they link it now. - #1712 (kevin9327): Kimi K3, Inkling and OLMoE now treat
max_tokens
as a ceiling like the other engines;coli chat's default of 16384
answered 400 on every Kimi and Inkling message against their 8192-token
window. - #1713 (kevin9327):
coli plan,doctorand--auto-tierexport the
variable that actually sizes the expert cache on Kimi K3
(K3_EXPERT_GB) and GLM-5.3 (GLM53_EXPERT_GB); onlyRAM_GBwas
exported, which neither engine reads as the cache size. - #1711 (kevin9327): on Windows, a Kimi K3
CUDA_DLLbuild and a HIP
host were refused by--gpuas CPU-only; the probe reads the backend DLL
name the host was built with, and the launcher maps--gpuonto Kimi's
K3_CUDA. - #1710 (kevin9327): a
tools[]entry whosefunctionis not an object
answered HTTP 500 from the GLM and DeepSeek renderers; it is the 400 that
generation_optionsalready had. - #1721 (monotophic): every frame the gateway writes to the engine is
checked, short writes are completed, and a failedCANCELorSTOP
drops the request's pending entry and answers a named 500 instead of a
silent close. - #1714, #1719 (benmaster82): the brio options form pins the shared
state, so per-question requests on one document read it once; the web
page can stop a scoring run, and duplicate options are removed on both
clients. - #1709 (kevin9327): regenerating a turn with pictures sends them again
and leaves the composer alone. - #1646 (Stamina9): qwen38 says once, on stderr, why the parallel expert
read path is not taken (disabled, cache smaller than the route, no FP8
scale bank, repeated expert, converted layout). - #1708 (wittchen): every
VK=1build of glm53 failed to compile on a
misplaced parenthesis. - #1707 (namespaceMarcello): the DeepSeek V4 unit objects rebuild when
the build flags change, so a CUDA engine build followed bymake test-c
no longer links the wrong objects (#1702). - #1715 (namespaceMarcello): seven GLM-5.3 harnesses matched the
unittest glob and counted as zero tests; they are renamed, a skip exits 2,
the two tiny oracles run in CI, and a discovery test catches the next
empty module (#1700). - #1622: DeepSeek V4's REAP checkpoints store each expert as six
per-matrix records; the engine read them through buffered pread and
counted every one as a direct-I/O fallback (36% of expert reads on the
150B, #1615). Each segment now goes through the aligned direct window,
with a regression on a generated per-matrix fixture. - #1597: a replayed tool call whose
argumentsparsed as JSON but was
not an object ("[1, 2]","5") answered HTTP 500 from the GLM renderers
before the engine was asked anything; it renders the call without
arguments, as every other renderer already did. - #1624: the five gcc 13 warnings left in
make checkare gone, and
st_index_loadrefuses an index path that would not fit its buffer
instead of opening a truncated one, with a long-path case in the tests. - #1651: a
pyflakespass over the launcher, autotune, the family
registry and the qwen36 converter: ameasure()defined twice, a
readlineimport without a fallback, a stray f-string, dead variables. - #1580:
make qwen36 CUDA_DLL=1on Windows reached GNU make's implicit
rule and built a CPU-only binary; a bareqwen36alias, a.build-config
prerequisite so a CUDA_DLL change rebuilds, a loader-against-header parity
test, and the Windows CUDA tier documented. - #1556:
coli planon macOS said "no supported GPU detected" on every
Mac; it now lists the Metal device by name, as identity only, without
pretending unified memory is a VRAM budget. - #1691: the installed launcher invoked as
/bin/colior/sbin/coli
on a merged-/usr system derived/libexec/colibriinstead of
/usr/libexec/colibri, becauseabspathkept the alias (#1689,
florin65's patch):realpathfirst. A test runs the launcher through
such an alias, and another checks that every root module the launcher
reaches is in themake installlist, the gap #1610 closed by hand.
Tools and the gateway
- #1425: a general GGUF reader, pure stdlib, and a converter from GGUF
OLMoE checkpoints to a colibri container, with the numerical evidence in
its own CI job. - #1497: opt-in prompt-injected tool calling for the families without
native tool tokens (OLMoE, Qwen3.6), behindCOLI_TOOL_FALLBACK=1, with a
two-turn end-to-end test. - #1355, #1357: durable per-request results and strict stdout
classification in the eval harness, and the logprob-gap check gated on
the engine preamble. - #1687:
GET /metricsin Prometheus text format, behind the API key:
four gauges, six outcome counters and four histograms (queue wait, slot
occupancy, first output, engine call), no request labels, no new
dependency. The admission scheduler distinguishes completion, failure
and cancellation, lets a request use a free slot that no earlier waiter
reserved, and joins the keepalive pump before the slot is released. - #1717 (enitimeago): the web chat offers Continue on the last
assistant message when it stopped at the token limit, by hand or on an
error, and only when/healthsays the server continues assistant
turns (#1699). - #1402 (enitimeago): a request whose last message is a non-empty
assistantturn continues that turn instead of answering in a new one, on
/v1/chat/completionsand/v1/messages, for all nine families (Kimi K3
frames the open turn engine-side); the prompt ends inside the turn as the
official template renders it without a generation cue. On by default,
COLI_CONTINUE_ASSISTANT=0restores the old behaviour; refused together
with tools or a turn ending in whitespace, with a 400 that says why. Each
renderer is pinned against the vendored template (#1401). - #1102 (monotophic): checkpoint-faithful FP8 containers that store
kv_b_projas fmt=8 could load but not decode attention; the absorb path
now decodes fmt=8 on CPU (bit-exact against the reference) and CUDA
(within the documented tolerance), and the kv_b sharding refuses by name
the formats it cannot serve, which also closes two silent misreads of
fmt=5 and fmt=6. - #1395 (rybruscoe):
COLI_EXACT_VERIFY=1makes the speculative verify
batch token-exact against sequential decode, at a measured cost on the
dot itself; off by default, the default path is unchanged. - #1720 (monotophic): a request carrying
seedis accepted and the seed
ignored, asdocs/api.mdnow says, instead of a 400; no determinism is
implied. - #1605:
ORACLE_STRICT=1makes a GLM oracle comparison exit non-zero
when it fails, token-exact by default withORACLE_TF_MAX_MISMATCHESfor
the documented teacher-forcing allowance; references are validated before
the comparison and non-finite logits cannot pass. Both oracle CI jobs run
real-process regressions against it. - #1705:
tools/benchmark_baseline.py, a collection protocol on top of
the HTTP harness for a repeated three-engine serving baseline: one frozen
manifest (hardware, model and template identity, per-engine launch
settings, cache and speculation policy), a rotating plan over a
concurrency matrix, one collector per engine and round that manages no
server, and a comparison that keeps failed and missing cells visible and
distinguishes matched artifacts from deployment comparisons. No results
are bundled and no ranking is emitted. - #1688:
tools/benchmark_http_serving.py, a stdlib HTTP streaming
benchmark over fixed JSONL conversations: closed-loop or paced arrivals
(periodic or Poisson, seeded), warmup separated from measurement,
first-output and duration SLOs, latency percentiles and usage-based
token throughput; a truncated or malformed stream is a failure, not a
sample.
Docs
- #1639, #1644: the README shows brio mode and the dashboard as it
is: the workspace, the Brain page (the measured expert atlas as a cortex,
and a region inside it) and the Profiling page, in four languages;
docs/api.mddescribes the four pages instead of the old console. - #1492, #1643: a Japanese README, and its banner at the shipping
version, which the banner test now checks in every language. - #1634: the multi-disk guide states measured gains and limits instead
of "twice the bandwidth", with Bash and PowerShell examples. - #1617: connecting the pi coding agent to
coli serve. - #1619:
expected_bytesidentity versus physical extent for
int4-rans256-g0 (#1273). - #1618 (bherald):
docs/qwen38.mdno longer calls the engine text-only;
the vision tower and the gateway image path shipped in 1.12.0. - #1649, #1647 (Suraj2105-1): the musl CI job runs on Alpine 3.24
and the release pipeline on Node.js 22, ahead of the 3.21 and Node 20
end of life. - #1568 (Yoruxyv): an Indonesian translation of the dashboard.
- #1681 (XBold): the README and
docs/qwen38.mdno longer say Qwen3.8
has no GPU backend; the CUDA VRAM expert tier and the int8 trunk in VRAM
shipped in 1.12.0.